blob: a87d202131e3c3505c6d386e56d24bc4354b4954 [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;
tomlu1cdcdf92018-01-16 11:07:51 -080033import com.google.devtools.build.lib.actions.ArtifactRoot;
felly9b91cb42019-06-04 09:35:21 -070034import com.google.devtools.build.lib.actions.CompletionContext;
Klaus Aehligee3e1922017-04-07 14:25:27 +000035import com.google.devtools.build.lib.actions.EventReportingArtifacts;
Googler17e28df2019-09-10 12:07:05 -070036import com.google.devtools.build.lib.actions.SpawnResult.MetadataLog;
ruperts76de73b2018-03-02 16:10:43 -080037import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040038import com.google.devtools.build.lib.analysis.BlazeDirectories;
janakr3b63a4e2017-09-14 09:55:40 +020039import com.google.devtools.build.lib.analysis.ServerDirectories;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040040import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040041import com.google.devtools.build.lib.analysis.config.BuildOptions;
gregcee495e6b2019-04-30 14:07:06 -070042import com.google.devtools.build.lib.analysis.config.CoreOptions;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040043import com.google.devtools.build.lib.analysis.config.FragmentOptions;
buchgr9e0308e2017-04-25 16:38:45 +020044import com.google.devtools.build.lib.buildeventstream.AnnounceBuildEventTransportsEvent;
Klaus Aehligee3e1922017-04-07 14:25:27 +000045import com.google.devtools.build.lib.buildeventstream.ArtifactGroupNamer;
Klaus Aehlig17325a12016-09-30 15:45:27 +000046import com.google.devtools.build.lib.buildeventstream.BuildEvent;
felly75a422a2019-01-17 14:52:49 -080047import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
ulfjack26e586d2018-05-17 08:42:13 -070048import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
Klaus Aehlig17325a12016-09-30 15:45:27 +000049import com.google.devtools.build.lib.buildeventstream.BuildEventId;
ulfjackfbf27562018-05-18 12:46:54 -070050import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
Klaus Aehligf75878d2016-11-21 13:41:16 +000051import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
Googlerd990a0a2019-05-13 16:46:42 -070052import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.Aborted.AbortReason;
Klaus Aehligee3e1922017-04-07 14:25:27 +000053import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.NamedSetOfFilesId;
Googler17e28df2019-09-10 12:07:05 -070054import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.File;
Klaus Aehlig17325a12016-09-30 15:45:27 +000055import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
lberkid2630092018-11-22 09:12:34 -080056import com.google.devtools.build.lib.buildeventstream.BuildEventTransportClosedEvent;
Klaus Aehliga708a022017-07-11 12:54:40 +020057import com.google.devtools.build.lib.buildeventstream.BuildEventWithConfiguration;
Klaus Aehligf75878d2016-11-21 13:41:16 +000058import com.google.devtools.build.lib.buildeventstream.BuildEventWithOrderConstraint;
Klaus Aehlig17325a12016-09-30 15:45:27 +000059import com.google.devtools.build.lib.buildeventstream.GenericBuildEvent;
Klaus Aehligee3e1922017-04-07 14:25:27 +000060import com.google.devtools.build.lib.buildeventstream.PathConverter;
Klaus Aehlig17325a12016-09-30 15:45:27 +000061import com.google.devtools.build.lib.buildeventstream.ProgressEvent;
ruperts76de73b2018-03-02 16:10:43 -080062import com.google.devtools.build.lib.buildeventstream.transports.BuildEventStreamOptions;
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +000063import com.google.devtools.build.lib.buildtool.BuildResult;
Klaus Aehlig17325a12016-09-30 15:45:27 +000064import com.google.devtools.build.lib.buildtool.buildevent.BuildCompleteEvent;
Googlerd990a0a2019-05-13 16:46:42 -070065import com.google.devtools.build.lib.buildtool.buildevent.NoAnalyzeEvent;
Klaus Aehligee3e1922017-04-07 14:25:27 +000066import com.google.devtools.build.lib.collect.nestedset.NestedSet;
67import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
68import com.google.devtools.build.lib.collect.nestedset.NestedSetView;
69import com.google.devtools.build.lib.testutil.FoundationTestCase;
Googlerd990a0a2019-05-13 16:46:42 -070070import com.google.devtools.build.lib.util.ExitCode;
felly17594762019-02-07 15:24:32 -080071import com.google.devtools.build.lib.util.Pair;
Klaus Aehligee3e1922017-04-07 14:25:27 +000072import com.google.devtools.build.lib.vfs.Path;
73import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080074import com.google.devtools.build.lib.vfs.Root;
Googler17e28df2019-09-10 12:07:05 -070075import com.google.devtools.build.lib.vfs.util.FileSystems;
ulfjackfbf27562018-05-18 12:46:54 -070076import com.google.devtools.common.options.Options;
Klaus Aehlig17325a12016-09-30 15:45:27 +000077import java.util.ArrayList;
Klaus Aehligf75878d2016-11-21 13:41:16 +000078import java.util.Collection;
buchgr9e0308e2017-04-25 16:38:45 +020079import java.util.Collections;
80import java.util.HashSet;
Klaus Aehlig17325a12016-09-30 15:45:27 +000081import java.util.List;
buchgr9e0308e2017-04-25 16:38:45 +020082import java.util.Set;
fellya4488a22019-04-03 13:05:47 -070083import java.util.concurrent.LinkedBlockingQueue;
84import java.util.concurrent.ThreadPoolExecutor;
lberkid2630092018-11-22 09:12:34 -080085import java.util.concurrent.TimeUnit;
fellya4488a22019-04-03 13:05:47 -070086import java.util.concurrent.atomic.AtomicInteger;
lberkid2630092018-11-22 09:12:34 -080087import java.util.concurrent.locks.LockSupport;
Googlerd990a0a2019-05-13 16:46:42 -070088import javax.annotation.Nullable;
fellya4488a22019-04-03 13:05:47 -070089import org.apache.commons.lang.time.StopWatch;
lpino0361ff62019-02-12 22:52:59 -080090import org.junit.After;
buchgr9e0308e2017-04-25 16:38:45 +020091import org.junit.Before;
fellya4488a22019-04-03 13:05:47 -070092import org.junit.Ignore;
Klaus Aehlig17325a12016-09-30 15:45:27 +000093import org.junit.Test;
94import org.junit.runner.RunWith;
95import org.junit.runners.JUnit4;
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +020096import org.mockito.Mockito;
buchgr9e0308e2017-04-25 16:38:45 +020097import org.mockito.MockitoAnnotations;
Klaus Aehlig17325a12016-09-30 15:45:27 +000098
99/** Tests {@link BuildEventStreamer}. */
100@RunWith(JUnit4.class)
Klaus Aehligee3e1922017-04-07 14:25:27 +0000101public class BuildEventStreamerTest extends FoundationTestCase {
lpino0361ff62019-02-12 22:52:59 -0800102 private CountingArtifactGroupNamer artifactGroupNamer;
103 private RecordingBuildEventTransport transport;
104 private BuildEventStreamer streamer;
105
106 @Before
107 public void setUp() {
108 artifactGroupNamer = new CountingArtifactGroupNamer();
fellya4488a22019-04-03 13:05:47 -0700109 transport = new RecordingBuildEventTransport(artifactGroupNamer, true);
lpino0361ff62019-02-12 22:52:59 -0800110 streamer =
lpino5bec36c2019-03-21 09:50:52 -0700111 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), artifactGroupNamer);
lpino0361ff62019-02-12 22:52:59 -0800112 }
113
114 @After
115 public void tearDown() {
116 artifactGroupNamer = null;
117 transport = null;
118 streamer = null;
119 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000120
Googler17e28df2019-09-10 12:07:05 -0700121 private static BuildEventContext getTestBuildEventContext(ArtifactGroupNamer artifactGroupNamer) {
122 return new BuildEventContext() {
123 @Override
124 public ArtifactGroupNamer artifactGroupNamer() {
125 return artifactGroupNamer;
126 }
127
128 @Override
129 public PathConverter pathConverter() {
130 return new PathConverter() {
131 @Override
132 public String apply(Path path) {
133 return path.toString();
134 }
135 };
136 }
137
138 @Override
139 public BuildEventProtocolOptions getOptions() {
140 return Options.getDefaults(BuildEventProtocolOptions.class);
141 }
142 };
143 }
144
ruperts76de73b2018-03-02 16:10:43 -0800145 private static final ActionExecutedEvent SUCCESSFUL_ACTION_EXECUTED_EVENT =
146 new ActionExecutedEvent(
ulfjack5f312dd2018-10-02 04:58:53 -0700147 ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
ruperts76de73b2018-03-02 16:10:43 -0800148 new ActionsTestUtil.NullAction(),
149 /* exception= */ null,
tomlud56a8062018-08-01 13:20:41 -0700150 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
ruperts76de73b2018-03-02 16:10:43 -0800151 /* stdout= */ null,
152 /* stderr= */ null,
Googler17e28df2019-09-10 12:07:05 -0700153 /* actionMetadataLogs= */ ImmutableList.of(),
felly3b050f62020-01-23 08:57:31 -0800154 ErrorTiming.NO_ERROR,
155 /* isInMemoryFs= */ false);
ruperts76de73b2018-03-02 16:10:43 -0800156
Klaus Aehlig17325a12016-09-30 15:45:27 +0000157 private static class RecordingBuildEventTransport implements BuildEventTransport {
Klaus Aehligee3e1922017-04-07 14:25:27 +0000158 private final List<BuildEvent> events = new ArrayList<>();
159 private final List<BuildEventStreamProtos.BuildEvent> eventsAsProtos = new ArrayList<>();
lpino0361ff62019-02-12 22:52:59 -0800160 private ArtifactGroupNamer artifactGroupNamer;
161
fellya4488a22019-04-03 13:05:47 -0700162 RecordingBuildEventTransport(ArtifactGroupNamer namer, boolean recordEvents) {
lpino0361ff62019-02-12 22:52:59 -0800163 this.artifactGroupNamer = namer;
164 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000165
166 @Override
buchgr9e0308e2017-04-25 16:38:45 +0200167 public String name() {
168 return this.getClass().getSimpleName();
169 }
170
171 @Override
felly6a8759f2019-07-09 11:27:03 -0700172 public boolean mayBeSlow() {
173 return false;
174 }
175
176 @Override
fellya4488a22019-04-03 13:05:47 -0700177 public synchronized void sendBuildEvent(BuildEvent event) {
Klaus Aehlig17325a12016-09-30 15:45:27 +0000178 events.add(event);
Googler17e28df2019-09-10 12:07:05 -0700179 eventsAsProtos.add(event.asStreamProto(getTestBuildEventContext(this.artifactGroupNamer)));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000180 }
181
182 @Override
buchgr9e0308e2017-04-25 16:38:45 +0200183 public ListenableFuture<Void> close() {
buchgr0b937432017-04-06 18:54:22 +0000184 return Futures.immediateFuture(null);
185 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000186
felly75a422a2019-01-17 14:52:49 -0800187 @Override
188 public BuildEventArtifactUploader getUploader() {
189 throw new IllegalStateException();
190 }
191
Klaus Aehlig17325a12016-09-30 15:45:27 +0000192 List<BuildEvent> getEvents() {
193 return events;
194 }
Klaus Aehligee3e1922017-04-07 14:25:27 +0000195
196 List<BuildEventStreamProtos.BuildEvent> getEventProtos() {
197 return eventsAsProtos;
198 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000199 }
200
Klaus Aehligf75878d2016-11-21 13:41:16 +0000201 private static class GenericOrderEvent implements BuildEventWithOrderConstraint {
202 private final BuildEventId id;
203 private final Collection<BuildEventId> children;
204 private final Collection<BuildEventId> after;
205
206 GenericOrderEvent(
207 BuildEventId id, Collection<BuildEventId> children, Collection<BuildEventId> after) {
208 this.id = id;
209 this.children = children;
210 this.after = after;
211 }
212
213 GenericOrderEvent(BuildEventId id, Collection<BuildEventId> children) {
214 this(id, children, children);
215 }
216
217 @Override
218 public BuildEventId getEventId() {
219 return id;
220 }
221
222 @Override
223 public Collection<BuildEventId> getChildrenEvents() {
224 return children;
225 }
226
227 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700228 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehligf75878d2016-11-21 13:41:16 +0000229 return GenericBuildEvent.protoChaining(this).build();
230 }
231
232 @Override
233 public Collection<BuildEventId> postedAfter() {
234 return after;
235 }
236 }
237
Klaus Aehligee3e1922017-04-07 14:25:27 +0000238 private static class GenericArtifactReportingEvent implements EventReportingArtifacts {
239 private final BuildEventId id;
240 private final Collection<BuildEventId> children;
241 private final Collection<NestedSet<Artifact>> artifacts;
242
243 GenericArtifactReportingEvent(
244 BuildEventId id,
245 Collection<BuildEventId> children,
246 Collection<NestedSet<Artifact>> artifacts) {
247 this.id = id;
248 this.children = children;
249 this.artifacts = artifacts;
250 }
251
252 GenericArtifactReportingEvent(BuildEventId id, Collection<NestedSet<Artifact>> artifacts) {
253 this(id, ImmutableSet.<BuildEventId>of(), artifacts);
254 }
255
256 @Override
257 public BuildEventId getEventId() {
258 return id;
259 }
260
261 @Override
262 public Collection<BuildEventId> getChildrenEvents() {
263 return children;
264 }
265
266 @Override
tomlu04e92812018-08-02 11:49:08 -0700267 public ReportedArtifacts reportedArtifacts() {
felly9b91cb42019-06-04 09:35:21 -0700268 return new ReportedArtifacts(artifacts, CompletionContext.FAILED_COMPLETION_CTX);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000269 }
270
271 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700272 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehligee3e1922017-04-07 14:25:27 +0000273 BuildEventStreamProtos.NamedSetOfFiles.Builder builder =
274 BuildEventStreamProtos.NamedSetOfFiles.newBuilder();
275 for (NestedSet<Artifact> artifactset : artifacts) {
276 builder.addFileSets(
277 converters
278 .artifactGroupNamer()
279 .apply((new NestedSetView<Artifact>(artifactset)).identifier()));
280 }
281 return GenericBuildEvent.protoChaining(this).setNamedSetOfFiles(builder.build()).build();
282 }
283 }
284
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400285 private static class GenericConfigurationEvent implements BuildEventWithConfiguration {
286 private final BuildEventId id;
287 private final Collection<BuildEventId> children;
Klaus Aehliga708a022017-07-11 12:54:40 +0200288 private final Collection<BuildEvent> configurations;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400289
290 GenericConfigurationEvent(
Klaus Aehliga708a022017-07-11 12:54:40 +0200291 BuildEventId id, Collection<BuildEventId> children, Collection<BuildEvent> configurations) {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400292 this.id = id;
293 this.children = children;
294 this.configurations = configurations;
295 }
296
Klaus Aehliga708a022017-07-11 12:54:40 +0200297 GenericConfigurationEvent(BuildEventId id, BuildEvent configuration) {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400298 this(id, ImmutableSet.<BuildEventId>of(), ImmutableSet.of(configuration));
299 }
300
301 @Override
302 public BuildEventId getEventId() {
303 return id;
304 }
305
306 @Override
307 public Collection<BuildEventId> getChildrenEvents() {
308 return children;
309 }
310
311 @Override
Klaus Aehliga708a022017-07-11 12:54:40 +0200312 public Collection<BuildEvent> getConfigurations() {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400313 return configurations;
314 }
315
316 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700317 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400318 return GenericBuildEvent.protoChaining(this).build();
319 }
320 }
321
Klaus Aehlig17325a12016-09-30 15:45:27 +0000322 private static BuildEventId testId(String opaque) {
323 return BuildEventId.unknownBuildEventId(opaque);
324 }
325
buchgr9e0308e2017-04-25 16:38:45 +0200326 private static class EventBusHandler {
327
328 Set<BuildEventTransport> transportSet;
329
330 @Subscribe
331 void transportsAnnounced(AnnounceBuildEventTransportsEvent evt) {
332 transportSet = Collections.synchronizedSet(new HashSet<>(evt.transports()));
333 }
lberkid2630092018-11-22 09:12:34 -0800334
335 @Subscribe
336 void transportClosed(BuildEventTransportClosedEvent evt) {
337 transportSet.remove(evt.transport());
338 }
buchgr9e0308e2017-04-25 16:38:45 +0200339 }
340
341 @Before
342 public void setup() {
343 MockitoAnnotations.initMocks(this);
344 }
345
346 @Test(timeout = 5000)
Klaus Aehlig17325a12016-09-30 15:45:27 +0000347 public void testSimpleStream() {
348 // Verify that a well-formed event is passed through and that completion of the
Klaus Aehligfb3c5722017-07-10 13:08:19 +0200349 // build clears the pending progress-update event. However, there is no guarantee
350 // on the order of the flushed events.
351 // Additionally, assert that the actual last event has the last_message flag set.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000352
buchgr9e0308e2017-04-25 16:38:45 +0200353 EventBusHandler handler = new EventBusHandler();
354 eventBus.register(handler);
lberkiaea56b32017-05-30 12:35:33 +0200355 assertThat(handler.transportSet).isNull();
buchgr9e0308e2017-04-25 16:38:45 +0200356
lpino5bec36c2019-03-21 09:50:52 -0700357 eventBus.post(new AnnounceBuildEventTransportsEvent(ImmutableSet.of(transport)));
358
Klaus Aehlig17325a12016-09-30 15:45:27 +0000359 BuildEvent startEvent =
360 new GenericBuildEvent(
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000361 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE,
362 BuildEventId.buildFinished()));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000363
364 streamer.buildEvent(startEvent);
365
aehlig03d55f32017-10-26 11:45:35 +0200366 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000367 List<BuildEvent> afterFirstEvent = transport.getEvents();
368 assertThat(afterFirstEvent).hasSize(1);
lberkiaea56b32017-05-30 12:35:33 +0200369 assertThat(afterFirstEvent.get(0).getEventId()).isEqualTo(startEvent.getEventId());
370 assertThat(handler.transportSet).hasSize(1);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000371
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000372 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000373
aehlig03d55f32017-10-26 11:45:35 +0200374 assertThat(streamer.isClosed()).isTrue();
lpino5bec36c2019-03-21 09:50:52 -0700375 eventBus.post(new BuildEventTransportClosedEvent(transport));
376
Klaus Aehlig17325a12016-09-30 15:45:27 +0000377 List<BuildEvent> finalStream = transport.getEvents();
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000378 assertThat(finalStream).hasSize(3);
Klaus Aehligfb3c5722017-07-10 13:08:19 +0200379 assertThat(ImmutableSet.of(finalStream.get(1).getEventId(), finalStream.get(2).getEventId()))
380 .isEqualTo(
381 ImmutableSet.of(BuildEventId.buildFinished(), ProgressEvent.INITIAL_PROGRESS_UPDATE));
382
383 // verify the "last_message" flag.
384 assertThat(transport.getEventProtos().get(0).getLastMessage()).isFalse();
385 assertThat(transport.getEventProtos().get(1).getLastMessage()).isFalse();
386 assertThat(transport.getEventProtos().get(2).getLastMessage()).isTrue();
lberkid2630092018-11-22 09:12:34 -0800387
388 while (!handler.transportSet.isEmpty()) {
389 LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
390 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000391 }
392
393 @Test
394 public void testChaining() {
395 // Verify that unannounced events are linked in with progress update events, assuming
396 // a correctly formed initial event.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000397 BuildEvent startEvent =
398 new GenericBuildEvent(
399 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
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(startEvent);
404 streamer.buildEvent(unexpectedEvent);
405
aehlig03d55f32017-10-26 11:45:35 +0200406 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000407 List<BuildEvent> eventsSeen = transport.getEvents();
408 assertThat(eventsSeen).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200409 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
410 assertThat(eventsSeen.get(2).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000411 BuildEvent linkEvent = eventsSeen.get(1);
lberkiaea56b32017-05-30 12:35:33 +0200412 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
413 assertWithMessage("Unexpected events should be linked")
414 .that(linkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
415 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000416 }
417
418 @Test
419 public void testBadInitialEvent() {
420 // Verify that, if the initial event does not announce the initial progress update event,
421 // the initial progress event is used instead to chain that event; in this way, new
422 // progress updates can always be chained in.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000423 BuildEvent unexpectedStartEvent =
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000424 new GenericBuildEvent(testId("unexpected start"), ImmutableSet.<BuildEventId>of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000425
426 streamer.buildEvent(unexpectedStartEvent);
427
428 List<BuildEvent> eventsSeen = transport.getEvents();
429 assertThat(eventsSeen).hasSize(2);
lberkiaea56b32017-05-30 12:35:33 +0200430 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(unexpectedStartEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000431 BuildEvent initial = eventsSeen.get(0);
lberkiaea56b32017-05-30 12:35:33 +0200432 assertThat(initial.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
433 assertWithMessage("Event should be linked")
434 .that(initial.getChildrenEvents().contains(unexpectedStartEvent.getEventId()))
435 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000436
437 // The initial event should also announce a new progress event; we test this
438 // by streaming another unannounced event.
439
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000440 BuildEvent unexpectedEvent =
441 new GenericBuildEvent(testId("unexpected"), ImmutableSet.<BuildEventId>of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000442
443 streamer.buildEvent(unexpectedEvent);
aehlig03d55f32017-10-26 11:45:35 +0200444
445 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000446 List<BuildEvent> allEventsSeen = transport.getEvents();
447 assertThat(allEventsSeen).hasSize(4);
lberkiaea56b32017-05-30 12:35:33 +0200448 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000449 BuildEvent secondLinkEvent = allEventsSeen.get(2);
lberkiaea56b32017-05-30 12:35:33 +0200450 assertWithMessage("Progress should have been announced")
451 .that(initial.getChildrenEvents().contains(secondLinkEvent.getEventId()))
452 .isTrue();
453 assertWithMessage("Second event should be linked")
454 .that(secondLinkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
455 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000456 }
457
458 @Test
459 public void testReferPastEvent() {
460 // Verify that, if an event is refers to a previously done event, that duplicated
461 // late-referenced event is not expected again.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000462 BuildEvent startEvent =
463 new GenericBuildEvent(
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000464 testId("Initial"),
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000465 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE,
466 BuildEventId.buildFinished()));
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000467 BuildEvent earlyEvent =
468 new GenericBuildEvent(testId("unexpected"), ImmutableSet.<BuildEventId>of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000469 BuildEvent lateReference =
470 new GenericBuildEvent(testId("late reference"), ImmutableSet.of(earlyEvent.getEventId()));
471
472 streamer.buildEvent(startEvent);
473 streamer.buildEvent(earlyEvent);
474 streamer.buildEvent(lateReference);
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000475 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000476
aehlig03d55f32017-10-26 11:45:35 +0200477 assertThat(streamer.isClosed()).isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000478 List<BuildEvent> eventsSeen = transport.getEvents();
479 int earlyEventCount = 0;
480 for (BuildEvent event : eventsSeen) {
481 if (event.getEventId().equals(earlyEvent.getEventId())) {
482 earlyEventCount++;
483 }
484 }
485 // The early event should be reported precisely once.
lberkiaea56b32017-05-30 12:35:33 +0200486 assertThat(earlyEventCount).isEqualTo(1);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000487 }
Klaus Aehligf75878d2016-11-21 13:41:16 +0000488
489 @Test
felly17594762019-02-07 15:24:32 -0800490 public void testReordering() {
Klaus Aehligf75878d2016-11-21 13:41:16 +0000491 // Verify that an event requiring to be posted after another one is indeed.
Klaus Aehligf75878d2016-11-21 13:41:16 +0000492 BuildEventId expectedId = testId("the target");
493 BuildEvent startEvent =
494 new GenericBuildEvent(
495 testId("Initial"),
496 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE, expectedId));
497 BuildEvent rootCause =
498 new GenericBuildEvent(testId("failure event"), ImmutableSet.<BuildEventId>of());
499 BuildEvent failedTarget =
500 new GenericOrderEvent(expectedId, ImmutableSet.<BuildEventId>of(rootCause.getEventId()));
501
502 streamer.buildEvent(startEvent);
503 streamer.buildEvent(failedTarget);
504 streamer.buildEvent(rootCause);
505
aehlig03d55f32017-10-26 11:45:35 +0200506 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligf75878d2016-11-21 13:41:16 +0000507 List<BuildEvent> allEventsSeen = transport.getEvents();
508 assertThat(allEventsSeen).hasSize(4);
lberkiaea56b32017-05-30 12:35:33 +0200509 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000510 BuildEvent linkEvent = allEventsSeen.get(1);
lberkiaea56b32017-05-30 12:35:33 +0200511 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
512 assertThat(allEventsSeen.get(2).getEventId()).isEqualTo(rootCause.getEventId());
513 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(failedTarget.getEventId());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000514 }
515
fellya4488a22019-04-03 13:05:47 -0700516 private static BuildEvent indexOrderedBuildEvent(int index, int afterIndex) {
517 return new GenericOrderEvent(
518 testId("Concurrent-" + index),
519 ImmutableList.of(),
520 afterIndex == -1
521 ? ImmutableList.of()
522 : ImmutableList.of(testId("Concurrent-" + afterIndex)));
523 }
524
525 @Test
526 public void testConcurrency() throws Exception {
527 // Verify that we can blast the BuildEventStreamer with many build events in parallel without
528 // violating internal consistency. The thread-safety under test is primarily sensitive to the
529 // pendingEvents field constructed when there are ordering constraints, so we make sure to
530 // include such ordering constraints in this test.
531 BuildEvent startEvent =
532 new GenericBuildEvent(
533 testId("Initial"),
534 ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
535 streamer.buildEvent(startEvent);
536
537 int numThreads = 12;
538 int numEventsPerThread = 10_000;
539 int totalEvents = numThreads * numEventsPerThread;
540 AtomicInteger idIndex = new AtomicInteger();
541 ThreadPoolExecutor pool =
542 new ThreadPoolExecutor(
543 numThreads,
544 numThreads,
545 /* keepAliveTime= */ 0,
546 TimeUnit.SECONDS,
547 /* workQueue= */ new LinkedBlockingQueue<>());
548
549 for (int i = 0; i < numThreads; i++) {
550 pool.execute(
551 () -> {
552 for (int j = 0; j < numEventsPerThread; j++) {
553 int index = idIndex.getAndIncrement();
554 // Arrange for half of the events to have an ordering constraint on the subsequent
555 // event. The ordering graph must avoid cycles.
556 int afterIndex = (index % 2 == 0) ? (index + 1) % totalEvents : -1;
557 streamer.buildEvent(indexOrderedBuildEvent(index, afterIndex));
558 }
559 });
560 }
561
562 pool.shutdown();
563 pool.awaitTermination(1, TimeUnit.DAYS);
564
565 BuildEventId lateId = testId("late event");
566 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId)));
567 assertThat(streamer.isClosed()).isFalse();
568 streamer.buildEvent(new GenericBuildEvent(lateId, ImmutableSet.of()));
569 assertThat(streamer.isClosed()).isTrue();
570
571 List<BuildEvent> eventsSeen = transport.getEvents();
572 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
573 assertThat(eventsSeen).hasSize(4 + totalEvents * 2);
574 }
575
576 // Re-enable this "test" for ad-hoc benchmarking of many concurrent build events.
577 @Ignore
578 public void concurrencyBenchmark() throws Exception {
579 long time = 0;
580 for (int iteration = 0; iteration < 3; iteration++) {
581 StopWatch watch = new StopWatch();
582 watch.start();
583
584 transport = new RecordingBuildEventTransport(artifactGroupNamer, /*recordEvents=*/ false);
585 streamer =
586 new BuildEventStreamer(
587 ImmutableSet.<BuildEventTransport>of(transport), artifactGroupNamer);
588 BuildEvent startEvent =
589 new GenericBuildEvent(
590 testId("Initial"),
591 ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
592 streamer.buildEvent(startEvent);
593
594 int numThreads = 12;
595 int numEventsPerThread = 100_000;
596 int totalEvents = numThreads * numEventsPerThread;
597 AtomicInteger idIndex = new AtomicInteger();
598 ThreadPoolExecutor pool =
599 new ThreadPoolExecutor(
600 numThreads, numThreads, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
601
602 for (int i = 0; i < numThreads; i++) {
603 pool.execute(
604 () -> {
605 for (int j = 0; j < numEventsPerThread; j++) {
606 int index = idIndex.getAndIncrement();
607 // Arrange for half of the events to have an ordering constraint on the subsequent
608 // event. The ordering graph must avoid cycles.
609 int afterIndex = (index % 2 == 0) ? (index + 1) % totalEvents : -1;
610 streamer.buildEvent(indexOrderedBuildEvent(index, afterIndex));
611 }
612 });
613 }
614
615 pool.shutdown();
616 pool.awaitTermination(1, TimeUnit.DAYS);
617 watch.stop();
618
619 time += watch.getTime();
620
621 BuildEventId lateId = testId("late event");
622 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId)));
623 assertThat(streamer.isClosed()).isFalse();
624 streamer.buildEvent(new GenericBuildEvent(lateId, ImmutableSet.of()));
625 assertThat(streamer.isClosed()).isTrue();
626 }
627
628 System.err.println();
629 System.err.println("=============================================================");
630 System.err.println("Concurrent performance of BEP build event processing: " + time + "ms");
631 System.err.println("=============================================================");
632 }
633
Klaus Aehligf75878d2016-11-21 13:41:16 +0000634 @Test
felly21c25822018-12-28 13:29:52 -0800635 public void testMissingPrerequisites() {
Klaus Aehligf75878d2016-11-21 13:41:16 +0000636 // Verify that an event where the prerequisite is never coming till the end of
637 // the build still gets posted, with the prerequisite aborted.
Klaus Aehligf75878d2016-11-21 13:41:16 +0000638 BuildEventId expectedId = testId("the target");
639 BuildEvent startEvent =
640 new GenericBuildEvent(
641 testId("Initial"),
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000642 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE, expectedId,
643 BuildEventId.buildFinished()));
Klaus Aehligf75878d2016-11-21 13:41:16 +0000644 BuildEventId rootCauseId = testId("failure event");
645 BuildEvent failedTarget =
646 new GenericOrderEvent(expectedId, ImmutableSet.<BuildEventId>of(rootCauseId));
647
648 streamer.buildEvent(startEvent);
649 streamer.buildEvent(failedTarget);
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000650 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
Klaus Aehligf75878d2016-11-21 13:41:16 +0000651
aehlig03d55f32017-10-26 11:45:35 +0200652 assertThat(streamer.isClosed()).isTrue();
Klaus Aehligf75878d2016-11-21 13:41:16 +0000653 List<BuildEvent> allEventsSeen = transport.getEvents();
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000654 assertThat(allEventsSeen).hasSize(6);
lberkiaea56b32017-05-30 12:35:33 +0200655 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
656 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(BuildEventId.buildFinished());
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000657 BuildEvent linkEvent = allEventsSeen.get(2);
lberkiaea56b32017-05-30 12:35:33 +0200658 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
659 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(rootCauseId);
660 assertThat(allEventsSeen.get(4).getEventId()).isEqualTo(failedTarget.getEventId());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000661 }
Klaus Aehligceb0f622017-03-20 13:52:06 +0000662
663 @Test
664 public void testVeryFirstEventNeedsToWait() {
665 // Verify that we can handle an first event waiting for another event.
Klaus Aehligceb0f622017-03-20 13:52:06 +0000666 BuildEventId initialId = testId("Initial");
667 BuildEventId waitId = testId("Waiting for initial event");
668 BuildEvent startEvent =
669 new GenericBuildEvent(
670 initialId,
671 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE, waitId));
672 BuildEvent waitingForStart =
673 new GenericOrderEvent(waitId, ImmutableSet.<BuildEventId>of(), ImmutableSet.of(initialId));
674
675 streamer.buildEvent(waitingForStart);
676 streamer.buildEvent(startEvent);
677
aehlig03d55f32017-10-26 11:45:35 +0200678 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligceb0f622017-03-20 13:52:06 +0000679 List<BuildEvent> allEventsSeen = transport.getEvents();
680 assertThat(allEventsSeen).hasSize(2);
lberkiaea56b32017-05-30 12:35:33 +0200681 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
682 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(waitingForStart.getEventId());
Klaus Aehligceb0f622017-03-20 13:52:06 +0000683 }
Klaus Aehligee3e1922017-04-07 14:25:27 +0000684
685 private Artifact makeArtifact(String pathString) {
686 Path path = outputBase.getRelative(PathFragment.create(pathString));
janakraea05602019-05-22 15:41:29 -0700687 return ActionsTestUtil.createArtifact(
688 ArtifactRoot.asSourceRoot(Root.fromPath(outputBase)), path);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000689 }
690
691 @Test
692 public void testReportedArtifacts() {
693 // Verify that reported artifacts are correctly unfolded into the stream
Klaus Aehligee3e1922017-04-07 14:25:27 +0000694 BuildEvent startEvent =
695 new GenericBuildEvent(
696 testId("Initial"),
697 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
698
699 Artifact a = makeArtifact("path/a");
700 Artifact b = makeArtifact("path/b");
701 Artifact c = makeArtifact("path/c");
702 NestedSet<Artifact> innerGroup = NestedSetBuilder.<Artifact>stableOrder().add(a).add(b).build();
703 NestedSet<Artifact> group =
704 NestedSetBuilder.<Artifact>stableOrder().addTransitive(innerGroup).add(c).build();
705 BuildEvent reportingArtifacts =
706 new GenericArtifactReportingEvent(testId("reporting"), ImmutableSet.of(group));
707
708 streamer.buildEvent(startEvent);
709 streamer.buildEvent(reportingArtifacts);
710
aehlig03d55f32017-10-26 11:45:35 +0200711 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligee3e1922017-04-07 14:25:27 +0000712 List<BuildEvent> allEventsSeen = transport.getEvents();
713 List<BuildEventStreamProtos.BuildEvent> eventProtos = transport.getEventProtos();
lberkiaea56b32017-05-30 12:35:33 +0200714 assertThat(allEventsSeen).hasSize(7);
715 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
716 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000717 List<BuildEventStreamProtos.File> firstSetDirects =
718 eventProtos.get(2).getNamedSetOfFiles().getFilesList();
lberkiaea56b32017-05-30 12:35:33 +0200719 assertThat(firstSetDirects).hasSize(2);
720 assertThat(ImmutableSet.of(firstSetDirects.get(0).getUri(), firstSetDirects.get(1).getUri()))
721 .isEqualTo(ImmutableSet.of(a.getPath().toString(), b.getPath().toString()));
Klaus Aehligee3e1922017-04-07 14:25:27 +0000722 List<NamedSetOfFilesId> secondSetTransitives =
723 eventProtos.get(4).getNamedSetOfFiles().getFileSetsList();
lberkiaea56b32017-05-30 12:35:33 +0200724 assertThat(secondSetTransitives).hasSize(1);
725 assertThat(secondSetTransitives.get(0)).isEqualTo(eventProtos.get(2).getId().getNamedSet());
Klaus Aehligee3e1922017-04-07 14:25:27 +0000726 List<NamedSetOfFilesId> reportedArtifactSets =
727 eventProtos.get(6).getNamedSetOfFiles().getFileSetsList();
lberkiaea56b32017-05-30 12:35:33 +0200728 assertThat(reportedArtifactSets).hasSize(1);
729 assertThat(reportedArtifactSets.get(0)).isEqualTo(eventProtos.get(4).getId().getNamedSet());
Klaus Aehligee3e1922017-04-07 14:25:27 +0000730 }
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200731
732 @Test
733 public void testStdoutReported() {
734 // Verify that stdout and stderr are reported in the build-event stream on progress
735 // events.
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200736 BuildEventStreamer.OutErrProvider outErr =
737 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
738 String stdoutMsg = "Some text that was written to stdout.";
739 String stderrMsg = "The UI text that bazel wrote to stderr.";
felly17594762019-02-07 15:24:32 -0800740 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg));
741 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg));
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200742 BuildEvent startEvent =
743 new GenericBuildEvent(
744 testId("Initial"),
745 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
746 BuildEvent unexpectedEvent =
747 new GenericBuildEvent(testId("unexpected"), ImmutableSet.<BuildEventId>of());
748
749 streamer.registerOutErrProvider(outErr);
750 streamer.buildEvent(startEvent);
751 streamer.buildEvent(unexpectedEvent);
752
aehlig03d55f32017-10-26 11:45:35 +0200753 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200754 List<BuildEvent> eventsSeen = transport.getEvents();
755 assertThat(eventsSeen).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200756 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
757 assertThat(eventsSeen.get(2).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200758 BuildEvent linkEvent = eventsSeen.get(1);
759 BuildEventStreamProtos.BuildEvent linkEventProto = transport.getEventProtos().get(1);
lberkiaea56b32017-05-30 12:35:33 +0200760 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
761 assertWithMessage("Unexpected events should be linked")
762 .that(linkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
763 .isTrue();
764 assertThat(linkEventProto.getProgress().getStdout()).isEqualTo(stdoutMsg);
765 assertThat(linkEventProto.getProgress().getStderr()).isEqualTo(stderrMsg);
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200766
767 // As there is only one progress event, the OutErrProvider should be queried
768 // only once for stdout and stderr.
769 verify(outErr, times(1)).getOut();
770 verify(outErr, times(1)).getErr();
771 }
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400772
773 @Test
felly21c25822018-12-28 13:29:52 -0800774 public void testStdoutReportedAfterCrash() {
775 // Verify that stdout and stderr are reported in the build-event stream on progress
776 // events.
felly21c25822018-12-28 13:29:52 -0800777 BuildEventStreamer.OutErrProvider outErr =
778 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
779 String stdoutMsg = "Some text that was written to stdout.";
780 String stderrMsg = "The UI text that bazel wrote to stderr.";
felly17594762019-02-07 15:24:32 -0800781 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg));
782 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg));
felly21c25822018-12-28 13:29:52 -0800783 BuildEvent startEvent =
784 new GenericBuildEvent(
785 testId("Initial"),
786 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
787
788 streamer.registerOutErrProvider(outErr);
789 streamer.buildEvent(startEvent);
790 // Simulate a crash with an abrupt call to #close().
791 streamer.close();
792 assertThat(streamer.isClosed()).isTrue();
793
794 List<BuildEvent> eventsSeen = transport.getEvents();
795 assertThat(eventsSeen).hasSize(2);
796 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
797 BuildEvent linkEvent = eventsSeen.get(1);
798 BuildEventStreamProtos.BuildEvent linkEventProto = transport.getEventProtos().get(1);
799 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
800 assertThat(linkEventProto.getProgress().getStdout()).isEqualTo(stdoutMsg);
801 assertThat(linkEventProto.getProgress().getStderr()).isEqualTo(stderrMsg);
802
803 // As there is only one progress event, the OutErrProvider should be queried
804 // only once for stdout and stderr.
805 verify(outErr, times(1)).getOut();
806 verify(outErr, times(1)).getErr();
807 }
808
felly17594762019-02-07 15:24:32 -0800809 private static <T> ImmutableList<ImmutableList<Pair<T, T>>> consumeToLists(
810 Iterable<T> left, Iterable<T> right) {
811 ImmutableList.Builder<Pair<T, T>> consumerBuilder = ImmutableList.builder();
812 ImmutableList.Builder<Pair<T, T>> lastConsumerBuilder = ImmutableList.builder();
813
814 BuildEventStreamer.consumeAsPairs(
815 left,
816 right,
817 (t1, t2) -> consumerBuilder.add(Pair.of(t1, t2)),
818 (t1, t2) -> lastConsumerBuilder.add(Pair.of(t1, t2)));
819
820 return ImmutableList.of(consumerBuilder.build(), lastConsumerBuilder.build());
821 }
822
823 @Test
824 public void testConsumeAsPairs() {
825 assertThat(consumeToLists(ImmutableList.of(1, 2, 3), ImmutableList.of(4, 5, 6)))
826 .containsExactly(
827 ImmutableList.of(Pair.of(1, null), Pair.of(2, null), Pair.of(3, 4), Pair.of(null, 5)),
828 ImmutableList.of(Pair.of(null, 6)))
829 .inOrder();
830
831 assertThat(consumeToLists(ImmutableList.of(), ImmutableList.of()))
832 .containsExactly(ImmutableList.of(), ImmutableList.of(Pair.of(null, null)))
833 .inOrder();
834
835 assertThat(consumeToLists(ImmutableList.of(1), ImmutableList.of(2)))
836 .containsExactly(ImmutableList.of(), ImmutableList.of(Pair.of(1, 2)))
837 .inOrder();
838
839 assertThat(consumeToLists(ImmutableList.of(1), ImmutableList.of(2, 3)))
840 .containsExactly(ImmutableList.of(Pair.of(1, 2)), ImmutableList.of(Pair.of(null, 3)))
841 .inOrder();
842
843 assertThat(consumeToLists(ImmutableList.of(1, 2), ImmutableList.of()))
844 .containsExactly(ImmutableList.of(Pair.of(1, null)), ImmutableList.of(Pair.of(2, null)))
845 .inOrder();
846
847 assertThat(consumeToLists(ImmutableList.of(), ImmutableList.of(1)))
848 .containsExactly(ImmutableList.of(), ImmutableList.of(Pair.of(null, 1)))
849 .inOrder();
850 }
851
felly21c25822018-12-28 13:29:52 -0800852 @Test
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400853 public void testReportedConfigurations() throws Exception {
854 // Verify that configuration events are posted, but only once.
mjhalupka5d7fa7b2018-03-22 13:37:38 -0700855 BuildOptions defaultBuildOptions =
gregcee495e6b2019-04-30 14:07:06 -0700856 BuildOptions.of(ImmutableList.<Class<? extends FragmentOptions>>of(CoreOptions.class));
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400857 BuildEvent startEvent =
858 new GenericBuildEvent(
859 testId("Initial"),
860 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
861 BuildConfiguration configuration =
862 new BuildConfiguration(
janakr3b63a4e2017-09-14 09:55:40 +0200863 new BlazeDirectories(
Klaus Aehligc2499c42018-02-27 05:47:21 -0800864 new ServerDirectories(outputBase, outputBase, outputBase),
865 rootDirectory,
cushon849df362018-05-14 01:51:45 -0700866 /* defaultSystemJavabase= */ null,
Klaus Aehligc2499c42018-02-27 05:47:21 -0800867 "productName"),
lberki406199f2018-04-09 03:16:19 -0700868 /* fragmentsMap= */ ImmutableMap
janakr3b63a4e2017-09-14 09:55:40 +0200869 .<Class<? extends BuildConfiguration.Fragment>, BuildConfiguration.Fragment>of(),
mjhalupka5d7fa7b2018-03-22 13:37:38 -0700870 defaultBuildOptions,
871 BuildOptions.diffForReconstruction(defaultBuildOptions, defaultBuildOptions),
lberki406199f2018-04-09 03:16:19 -0700872 /* reservedActionMnemonics= */ ImmutableSet.of(),
lberki86266232018-04-11 00:33:42 -0700873 ActionEnvironment.EMPTY,
gregce85297462017-08-18 21:20:29 +0200874 "workspace");
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400875 BuildEvent firstWithConfiguration =
shahan50f99d52018-03-10 05:14:09 -0800876 new GenericConfigurationEvent(testId("first"), configuration.toBuildEvent());
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400877 BuildEvent secondWithConfiguration =
shahan50f99d52018-03-10 05:14:09 -0800878 new GenericConfigurationEvent(testId("second"), configuration.toBuildEvent());
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400879
880 streamer.buildEvent(startEvent);
881 streamer.buildEvent(firstWithConfiguration);
882 streamer.buildEvent(secondWithConfiguration);
883
aehlig03d55f32017-10-26 11:45:35 +0200884 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400885 List<BuildEvent> allEventsSeen = transport.getEvents();
lberkiaea56b32017-05-30 12:35:33 +0200886 assertThat(allEventsSeen).hasSize(7);
887 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
888 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
shahan50f99d52018-03-10 05:14:09 -0800889 assertThat(allEventsSeen.get(2)).isEqualTo(configuration.toBuildEvent());
lberkiaea56b32017-05-30 12:35:33 +0200890 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(BuildEventId.progressId(1));
891 assertThat(allEventsSeen.get(4)).isEqualTo(firstWithConfiguration);
892 assertThat(allEventsSeen.get(5).getEventId()).isEqualTo(BuildEventId.progressId(2));
893 assertThat(allEventsSeen.get(6)).isEqualTo(secondWithConfiguration);
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400894 }
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200895
896 @Test
897 public void testEarlyFlush() throws Exception {
898 // Verify that the streamer can handle early calls to flush() and still correctly
899 // reports stdout and stderr in the build-event stream.
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200900 BuildEventStreamer.OutErrProvider outErr =
901 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
902 String firstStdoutMsg = "Some text that was written to stdout.";
903 String firstStderrMsg = "The UI text that bazel wrote to stderr.";
904 String secondStdoutMsg = "More text that was written to stdout, still before the start event.";
905 String secondStderrMsg = "More text written to stderr, still before the start event.";
felly17594762019-02-07 15:24:32 -0800906 when(outErr.getOut())
907 .thenReturn(ImmutableList.of(firstStdoutMsg))
908 .thenReturn(ImmutableList.of(secondStdoutMsg));
909 when(outErr.getErr())
910 .thenReturn(ImmutableList.of(firstStderrMsg))
911 .thenReturn(ImmutableList.of(secondStderrMsg));
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200912 BuildEvent startEvent =
913 new GenericBuildEvent(
914 testId("Initial"),
915 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
916
917 streamer.registerOutErrProvider(outErr);
918 streamer.flush();
919 streamer.flush();
920 streamer.buildEvent(startEvent);
921
aehlig03d55f32017-10-26 11:45:35 +0200922 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200923 List<BuildEvent> eventsSeen = transport.getEvents();
924 assertThat(eventsSeen).hasSize(3);
925 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
926 BuildEvent progressEvent = eventsSeen.get(1);
927 assertThat(progressEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
928 BuildEventStreamProtos.BuildEvent progressEventProto = transport.getEventProtos().get(1);
929 assertThat(progressEventProto.getProgress().getStdout()).isEqualTo(firstStdoutMsg);
930 assertThat(progressEventProto.getProgress().getStderr()).isEqualTo(firstStderrMsg);
931 BuildEventStreamProtos.BuildEvent secondProgressEventProto = transport.getEventProtos().get(2);
932 assertThat(secondProgressEventProto.getProgress().getStdout()).isEqualTo(secondStdoutMsg);
933 assertThat(secondProgressEventProto.getProgress().getStderr()).isEqualTo(secondStderrMsg);
934
935 // As there is only one progress event, the OutErrProvider should be queried
936 // only once per flush() for stdout and stderr.
937 verify(outErr, times(2)).getOut();
938 verify(outErr, times(2)).getErr();
939 }
940
941 @Test
felly17594762019-02-07 15:24:32 -0800942 public void testChunkedFlush() throws Exception {
943 // Verify that the streamer calls to flush() that return multiple chunked buffers.
felly17594762019-02-07 15:24:32 -0800944 BuildEventStreamer.OutErrProvider outErr =
945 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
946 String firstStdoutMsg = "Some text that was written to stdout.";
947 String firstStderrMsg = "The UI text that bazel wrote to stderr.";
948 String secondStdoutMsg = "More text that was written to stdout, still before the start event.";
949 String secondStderrMsg = "More text written to stderr, still before the start event.";
950 when(outErr.getOut()).thenReturn(ImmutableList.of(firstStdoutMsg, secondStdoutMsg));
951 when(outErr.getErr()).thenReturn(ImmutableList.of(firstStderrMsg, secondStderrMsg));
952 BuildEvent startEvent =
953 new GenericBuildEvent(
954 testId("Initial"),
955 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
956
957 streamer.registerOutErrProvider(outErr);
958 streamer.buildEvent(startEvent);
959 streamer.flush();
960
961 assertThat(streamer.isClosed()).isFalse();
962 List<BuildEvent> eventsSeen = transport.getEvents();
963 assertThat(eventsSeen).hasSize(4);
964 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
965
966 // Expect to find 3 progress messages: (firstStdout, ""), (secondStdout, firstStderr),
967 // ("", secondStdErr). Assuming UIs display stdout first, this maintains ordering.
968 BuildEvent progressEvent = eventsSeen.get(1);
969 assertThat(progressEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
970 BuildEventStreamProtos.BuildEvent progressEventProto = transport.getEventProtos().get(1);
971 assertThat(progressEventProto.getProgress().getStdout()).isEqualTo(firstStdoutMsg);
972 assertThat(progressEventProto.getProgress().getStderr()).isEmpty();
973
974 BuildEventStreamProtos.BuildEvent secondProgressEventProto = transport.getEventProtos().get(2);
975 assertThat(secondProgressEventProto.getProgress().getStdout()).isEqualTo(secondStdoutMsg);
976 assertThat(secondProgressEventProto.getProgress().getStderr()).isEqualTo(firstStderrMsg);
977
978 BuildEventStreamProtos.BuildEvent thirdProgressEventProto = transport.getEventProtos().get(3);
979 assertThat(thirdProgressEventProto.getProgress().getStdout()).isEmpty();
980 assertThat(thirdProgressEventProto.getProgress().getStderr()).isEqualTo(secondStderrMsg);
981
982 // The OutErrProvider should be queried only once per flush().
983 verify(outErr, times(1)).getOut();
984 verify(outErr, times(1)).getErr();
985 }
986
987 @Test
Klaus Aehlig28221ff2018-01-11 04:28:00 -0800988 public void testNoopFlush() throws Exception {
989 // Verify that the streamer ignores a flush, if neither stream produces any output.
Klaus Aehlig28221ff2018-01-11 04:28:00 -0800990 BuildEventStreamer.OutErrProvider outErr =
991 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
992 String stdoutMsg = "Some text that was written to stdout.";
993 String stderrMsg = "The UI text that bazel wrote to stderr.";
felly17594762019-02-07 15:24:32 -0800994 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg)).thenReturn(ImmutableList.of());
995 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg)).thenReturn(ImmutableList.of());
Klaus Aehlig28221ff2018-01-11 04:28:00 -0800996 BuildEvent startEvent =
997 new GenericBuildEvent(
998 testId("Initial"),
999 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
1000
1001 streamer.registerOutErrProvider(outErr);
1002 streamer.buildEvent(startEvent);
1003 assertThat(transport.getEvents()).hasSize(1);
1004 streamer.flush(); // Output, so a new progress event has to be added
1005 assertThat(transport.getEvents()).hasSize(2);
1006 streamer.flush(); // No further output, so no additional event should be generated.
1007 assertThat(transport.getEvents()).hasSize(2);
1008
1009 assertThat(transport.getEvents().get(0)).isEqualTo(startEvent);
1010 assertThat(transport.getEventProtos().get(1).getProgress().getStdout()).isEqualTo(stdoutMsg);
1011 assertThat(transport.getEventProtos().get(1).getProgress().getStderr()).isEqualTo(stderrMsg);
1012 }
1013
1014 @Test
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001015 public void testEarlyFlushBadInitialEvent() throws Exception {
1016 // Verify that an early flush works correctly with an unusual start event.
1017 // In this case, we expect 3 events in the stream, in that order:
jingwen68c57f02018-11-21 16:17:17 -08001018 // - an artificial progress event as initial event, to properly link in
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001019 // all events
1020 // - the unusal first event we have seen, and
1021 // - a progress event reporting the flushed messages.
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001022 BuildEventStreamer.OutErrProvider outErr =
1023 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
1024 String stdoutMsg = "Some text that was written to stdout.";
1025 String stderrMsg = "The UI text that bazel wrote to stderr.";
felly17594762019-02-07 15:24:32 -08001026 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg));
1027 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg));
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001028
1029 BuildEvent unexpectedStartEvent =
1030 new GenericBuildEvent(testId("unexpected start"), ImmutableSet.<BuildEventId>of());
1031
1032 streamer.registerOutErrProvider(outErr);
1033 streamer.flush();
1034 streamer.buildEvent(unexpectedStartEvent);
1035
aehlig03d55f32017-10-26 11:45:35 +02001036 assertThat(streamer.isClosed()).isFalse();
1037
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001038 List<BuildEvent> eventsSeen = transport.getEvents();
1039 assertThat(eventsSeen).hasSize(3);
1040
1041 BuildEvent initial = eventsSeen.get(0);
1042 assertThat(initial.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
1043 BuildEventStreamProtos.BuildEvent initialProto = transport.getEventProtos().get(0);
1044 assertThat(initialProto.getProgress().getStdout()).isEmpty();
1045 assertThat(initialProto.getProgress().getStderr()).isEmpty();
1046
1047 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(unexpectedStartEvent.getEventId());
1048 assertWithMessage("Unexpected event should be linked")
1049 .that(initial.getChildrenEvents().contains(unexpectedStartEvent.getEventId()))
1050 .isTrue();
1051
1052 BuildEventStreamProtos.BuildEvent progressProto = transport.getEventProtos().get(2);
1053 assertThat(progressProto.getProgress().getStdout()).isEqualTo(stdoutMsg);
1054 assertThat(progressProto.getProgress().getStderr()).isEqualTo(stderrMsg);
1055 assertWithMessage("flushed progress should be linked")
1056 .that(initial.getChildrenEvents().contains(eventsSeen.get(2).getEventId()))
1057 .isTrue();
1058
1059 verify(outErr, times(1)).getOut();
1060 verify(outErr, times(1)).getErr();
1061 }
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001062
1063 @Test
1064 public void testEarlyAbort() throws Exception {
1065 // For a build that is aborted before a build-started event is generated,
1066 // we still expect that, if a build-started event is forced by some order
1067 // constraint (e.g., CommandLine wants to come after build started), then
1068 // that gets sorted to the beginning.
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001069 BuildEvent orderEvent =
1070 new GenericOrderEvent(
1071 testId("event depending on start"),
1072 ImmutableList.of(),
1073 ImmutableList.of(BuildEventId.buildStartedId()));
1074
1075 streamer.buildEvent(orderEvent);
1076 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
1077
aehlig03d55f32017-10-26 11:45:35 +02001078 assertThat(streamer.isClosed()).isTrue();
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001079 List<BuildEvent> eventsSeen = transport.getEvents();
1080 assertThat(eventsSeen).hasSize(4);
1081 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(BuildEventId.buildStartedId());
1082 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(orderEvent.getEventId());
1083 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
1084 .isEqualTo(
1085 ImmutableSet.of(BuildEventId.buildFinished(), ProgressEvent.INITIAL_PROGRESS_UPDATE));
1086 assertThat(transport.getEventProtos().get(3).getLastMessage()).isTrue();
1087 }
aehlig03d55f32017-10-26 11:45:35 +02001088
1089 @Test
1090 public void testFinalEventsLate() throws Exception {
1091 // Verify that we correctly handle late events (i.e., events coming only after the
1092 // BuildCompleteEvent) that are sent to the streamer after the BuildCompleteEvent.
aehlig03d55f32017-10-26 11:45:35 +02001093 BuildEvent startEvent =
1094 new GenericBuildEvent(
1095 testId("Initial"),
1096 ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1097 BuildEventId lateId = testId("late event");
1098 BuildEvent finishedEvent = new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId));
1099
1100 streamer.buildEvent(startEvent);
1101 streamer.buildEvent(finishedEvent);
1102 assertThat(streamer.isClosed()).isFalse();
1103 streamer.buildEvent(new GenericBuildEvent(lateId, ImmutableSet.of()));
1104 assertThat(streamer.isClosed()).isTrue();
1105
1106 List<BuildEvent> eventsSeen = transport.getEvents();
1107 assertThat(eventsSeen).hasSize(4);
1108 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
1109 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(BuildEventId.buildFinished());
1110 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
1111 .isEqualTo(ImmutableSet.of(lateId, ProgressEvent.INITIAL_PROGRESS_UPDATE));
1112 }
1113
1114 @Test
1115 public void testFinalEventsEarly() throws Exception {
1116 // Verify that we correctly handle late events (i.e., events coming only after the
1117 // BuildCompleteEvent) that are sent to the streamer before the BuildCompleteEvent,
1118 // but with an order constraint to come afterwards.
aehlig03d55f32017-10-26 11:45:35 +02001119 BuildEvent startEvent =
1120 new GenericBuildEvent(
1121 testId("Initial"),
1122 ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1123 BuildEventId lateId = testId("late event");
1124 BuildEvent finishedEvent = new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId));
1125
1126 streamer.buildEvent(startEvent);
1127 streamer.buildEvent(
1128 new GenericOrderEvent(
1129 lateId, ImmutableSet.of(), ImmutableList.of(BuildEventId.buildFinished())));
1130 streamer.buildEvent(finishedEvent);
1131 assertThat(streamer.isClosed()).isTrue();
1132
1133 List<BuildEvent> eventsSeen = transport.getEvents();
1134 assertThat(eventsSeen).hasSize(4);
1135 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
1136 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(BuildEventId.buildFinished());
1137 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
1138 .isEqualTo(ImmutableSet.of(lateId, ProgressEvent.INITIAL_PROGRESS_UPDATE));
1139 }
ruperts76de73b2018-03-02 16:10:43 -08001140
1141 @Test
1142 public void testSuccessfulActionsAreNotPublishedByDefault() {
1143 EventBusHandler handler = new EventBusHandler();
1144 eventBus.register(handler);
1145
ruperts76de73b2018-03-02 16:10:43 -08001146 ActionExecutedEvent failedActionExecutedEvent =
1147 new ActionExecutedEvent(
ulfjack5f312dd2018-10-02 04:58:53 -07001148 ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
ruperts76de73b2018-03-02 16:10:43 -08001149 new ActionsTestUtil.NullAction(),
1150 new ActionExecutionException("Exception", /* action= */ null, /* catastrophe= */ false),
tomlud56a8062018-08-01 13:20:41 -07001151 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
ruperts76de73b2018-03-02 16:10:43 -08001152 /* stdout= */ null,
1153 /* stderr= */ null,
Googler17e28df2019-09-10 12:07:05 -07001154 /* actionMetadataLogs= */ ImmutableList.of(),
felly3b050f62020-01-23 08:57:31 -08001155 ErrorTiming.BEFORE_EXECUTION,
1156 /* isInMemoryFs= */ false);
ruperts76de73b2018-03-02 16:10:43 -08001157
1158 streamer.buildEvent(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1159 streamer.buildEvent(failedActionExecutedEvent);
1160
1161 List<BuildEvent> transportedEvents = transport.getEvents();
1162
1163 assertThat(transportedEvents).doesNotContain(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1164 assertThat(transportedEvents).contains(failedActionExecutedEvent);
1165 }
1166
1167 @Test
1168 public void testSuccessfulActionsCanBePublished() {
1169 EventBusHandler handler = new EventBusHandler();
1170 eventBus.register(handler);
1171
1172 BuildEventStreamOptions options = new BuildEventStreamOptions();
1173 options.publishAllActions = true;
1174
ruperts76de73b2018-03-02 16:10:43 -08001175 BuildEventStreamer streamer =
lpino2bf89062019-02-21 03:24:49 -08001176 new BuildEventStreamer.Builder()
1177 .artifactGroupNamer(artifactGroupNamer)
1178 .besStreamOptions(options)
lpino2bf89062019-02-21 03:24:49 -08001179 .buildEventTransports(ImmutableSet.of(transport))
1180 .build();
ruperts76de73b2018-03-02 16:10:43 -08001181
1182 ActionExecutedEvent failedActionExecutedEvent =
1183 new ActionExecutedEvent(
ulfjack5f312dd2018-10-02 04:58:53 -07001184 ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
ruperts76de73b2018-03-02 16:10:43 -08001185 new ActionsTestUtil.NullAction(),
1186 new ActionExecutionException("Exception", /* action= */ null, /* catastrophe= */ false),
tomlud56a8062018-08-01 13:20:41 -07001187 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
ruperts76de73b2018-03-02 16:10:43 -08001188 /* stdout= */ null,
1189 /* stderr= */ null,
Googler17e28df2019-09-10 12:07:05 -07001190 /* actionMetadataLogs= */ ImmutableList.of(),
felly3b050f62020-01-23 08:57:31 -08001191 ErrorTiming.BEFORE_EXECUTION,
1192 /* isInMemoryFs= */ false);
ruperts76de73b2018-03-02 16:10:43 -08001193
1194 streamer.buildEvent(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1195 streamer.buildEvent(failedActionExecutedEvent);
1196
1197 List<BuildEvent> transportedEvents = transport.getEvents();
1198
1199 assertThat(transportedEvents).contains(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1200 assertThat(transportedEvents).contains(failedActionExecutedEvent);
1201 }
Googlerd990a0a2019-05-13 16:46:42 -07001202
1203 @Test
1204 public void testBuildIncomplete() {
1205 BuildEventId buildEventId = testId("abort_expected");
1206 BuildEvent startEvent =
1207 new GenericBuildEvent(
1208 BuildEventId.buildStartedId(),
1209 ImmutableSet.of(
1210 buildEventId, ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1211 BuildCompleteEvent buildCompleteEvent =
1212 buildCompleteEvent(ExitCode.BUILD_FAILURE, true, null, false);
1213
1214 streamer.buildEvent(startEvent);
1215 streamer.buildEvent(buildCompleteEvent);
1216 streamer.close();
1217
1218 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1219 assertThat(aborted).isNotNull();
1220 assertThat(aborted.hasAborted()).isNotNull();
1221 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INCOMPLETE);
1222 assertThat(aborted.getAborted().getDescription()).isEmpty();
1223 }
1224
1225 @Test
1226 public void testBuildCrash() {
1227 BuildEventId buildEventId = testId("abort_expected");
1228 BuildEvent startEvent =
1229 new GenericBuildEvent(
1230 BuildEventId.buildStartedId(),
1231 ImmutableSet.of(
1232 buildEventId, ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1233 BuildCompleteEvent buildCompleteEvent =
1234 buildCompleteEvent(ExitCode.BUILD_FAILURE, true, new RuntimeException(), false);
1235
1236 streamer.buildEvent(startEvent);
1237 streamer.buildEvent(buildCompleteEvent);
1238 streamer.close();
1239
1240 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1241 assertThat(aborted).isNotNull();
1242 assertThat(aborted.hasAborted()).isNotNull();
1243 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INTERNAL);
1244 assertThat(aborted.getAborted().getDescription()).isEmpty();
1245 }
1246
1247 @Test
1248 public void testBuildCatastrophe() {
1249 BuildEventId buildEventId = testId("abort_expected");
1250 BuildEvent startEvent =
1251 new GenericBuildEvent(
1252 BuildEventId.buildStartedId(),
1253 ImmutableSet.of(
1254 buildEventId, ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1255 BuildCompleteEvent buildCompleteEvent =
1256 buildCompleteEvent(ExitCode.BUILD_FAILURE, true, null, true);
1257
1258 streamer.buildEvent(startEvent);
1259 streamer.buildEvent(buildCompleteEvent);
1260 streamer.close();
1261
1262 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1263 assertThat(aborted).isNotNull();
1264 assertThat(aborted.hasAborted()).isNotNull();
1265 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INTERNAL);
1266 assertThat(aborted.getAborted().getDescription()).isEmpty();
1267 }
1268
1269 @Test
1270 public void testStreamAbortedWithTimeout() {
1271 BuildEventId buildEventId = testId("abort_expected");
1272 BuildEvent startEvent =
1273 new GenericBuildEvent(
1274 BuildEventId.buildStartedId(),
1275 ImmutableSet.of(
1276 buildEventId, ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1277
1278 streamer.buildEvent(startEvent);
1279 streamer.close(AbortReason.TIME_OUT);
1280
1281 BuildEventStreamProtos.BuildEvent aborted0 = getBepEvent(buildEventId);
1282 assertThat(aborted0).isNotNull();
1283 assertThat(aborted0.hasAborted()).isNotNull();
1284 assertThat(aborted0.getAborted().getReason()).isEqualTo(AbortReason.TIME_OUT);
1285 assertThat(aborted0.getAborted().getDescription()).isEmpty();
1286
1287 BuildEventStreamProtos.BuildEvent aborted1 = getBepEvent(BuildEventId.buildFinished());
1288 assertThat(aborted1).isNotNull();
1289 assertThat(aborted1.hasAborted()).isNotNull();
1290 assertThat(aborted1.getAborted().getReason()).isEqualTo(AbortReason.TIME_OUT);
1291 assertThat(aborted1.getAborted().getDescription()).isEmpty();
1292 }
1293
1294 @Test
1295 public void testBuildFailureMultipleReasons() {
1296 BuildEventId buildEventId = testId("abort_expected");
1297 BuildEvent startEvent =
1298 new GenericBuildEvent(
1299 BuildEventId.buildStartedId(),
1300 ImmutableSet.of(
1301 buildEventId, ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1302 BuildCompleteEvent buildCompleteEvent =
1303 buildCompleteEvent(ExitCode.BUILD_FAILURE, false, new RuntimeException(), false);
1304
1305 streamer.buildEvent(startEvent);
1306 streamer.noAnalyze(new NoAnalyzeEvent());
1307 streamer.buildEvent(buildCompleteEvent);
1308 streamer.close();
1309
1310 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1311 assertThat(aborted).isNotNull();
1312 assertThat(aborted.hasAborted()).isNotNull();
1313 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INTERNAL);
1314 assertThat(aborted.getAborted().getDescription())
1315 .isEqualTo("Multiple abort reasons reported: [NO_ANALYZE, INTERNAL]");
1316 }
1317
1318 @Nullable
1319 private BuildEventStreamProtos.BuildEvent getBepEvent(BuildEventId buildEventId) {
1320 return transport.getEventProtos().stream()
1321 .filter(e -> e.getId().equals(buildEventId.asStreamProto()))
1322 .findFirst()
1323 .orElse(null);
1324 }
1325
1326 private BuildCompleteEvent buildCompleteEvent(
1327 ExitCode exitCode, boolean stopOnFailure, Throwable crash, boolean catastrophe) {
1328 BuildResult result = new BuildResult(0);
1329 result.setExitCondition(exitCode);
1330 result.setStopOnFirstFailure(stopOnFailure);
1331 if (catastrophe) {
1332 result.setCatastrophe();
1333 }
1334 if (crash != null) {
1335 result.setUnhandledThrowable(crash);
1336 }
1337 return new BuildCompleteEvent(result);
1338 }
Googler17e28df2019-09-10 12:07:05 -07001339
1340 private static ActionExecutedEvent createActionExecutedEventWithLogs(
1341 ImmutableList<MetadataLog> metadataLogs) {
1342 return new ActionExecutedEvent(
1343 ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
1344 new ActionsTestUtil.NullAction(),
1345 /* exception= */ null,
1346 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
1347 /* stdout= */ null,
1348 /* stderr= */ null,
1349 metadataLogs,
felly3b050f62020-01-23 08:57:31 -08001350 ErrorTiming.NO_ERROR,
1351 /* isInMemoryFs= */ false);
Googler17e28df2019-09-10 12:07:05 -07001352 }
1353
1354 @Test
1355 public void testActionExecutedEventLogsConstructor() {
1356 String metadataLogName = "action_metadata";
1357 Path testPath1 = FileSystems.getJavaIoFileSystem().getPath("/path/to/logs-1");
1358 Path testPath2 = FileSystems.getJavaIoFileSystem().getPath("/path/to/logs-2");
1359 MetadataLog testMetadataLog1 = new MetadataLog(metadataLogName, testPath1);
1360 MetadataLog testMetadataLog2 = new MetadataLog(metadataLogName, testPath2);
1361
1362 ActionExecutedEvent withLogsEvent =
1363 createActionExecutedEventWithLogs(ImmutableList.of(testMetadataLog1, testMetadataLog2));
1364 ActionExecutedEvent withNoLogsEvent = SUCCESSFUL_ACTION_EXECUTED_EVENT;
1365
1366 assertWithMessage("List parameter should return list of log path values")
1367 .that(withLogsEvent.getActionMetadataLogs())
1368 .containsExactly(testMetadataLog1, testMetadataLog2);
1369 assertWithMessage("Null logs parameter should return empty list.")
1370 .that(withNoLogsEvent.getActionMetadataLogs())
1371 .isEmpty();
1372 }
1373
1374 @Test
1375 public void testActionExcutedEventProtoLogs() {
1376 String metadataLogName = "action_metadata";
1377 Path testPath1 = FileSystems.getJavaIoFileSystem().getPath("/path/to/logs-1");
1378 Path testPath2 = FileSystems.getJavaIoFileSystem().getPath("/path/to/logs-2");
1379
1380 ActionExecutedEvent withLogsEvent =
1381 createActionExecutedEventWithLogs(
1382 ImmutableList.of(
1383 new MetadataLog(metadataLogName, testPath1),
1384 new MetadataLog(metadataLogName, testPath2)));
1385 ActionExecutedEvent withNoLogsEvents = SUCCESSFUL_ACTION_EXECUTED_EVENT;
1386
1387 BuildEventStreamProtos.BuildEvent buildEventLogs =
1388 withLogsEvent.asStreamProto(getTestBuildEventContext(artifactGroupNamer));
1389 BuildEventStreamProtos.BuildEvent buildEventNoLogs =
1390 withNoLogsEvents.asStreamProto(getTestBuildEventContext(artifactGroupNamer));
1391
1392 assertWithMessage("With logs build event action should contain 2 log files")
1393 .that(buildEventLogs.getAction().getActionMetadataLogsCount())
1394 .isEqualTo(2);
1395 assertWithMessage("No logs build event action should contain 0 log files")
1396 .that(buildEventNoLogs.getAction().getActionMetadataLogsCount())
1397 .isEqualTo(0);
1398 assertWithMessage("Event action should contains the two paths")
1399 .that(
1400 buildEventLogs.getAction().getActionMetadataLogsList().stream()
1401 .map(File::getUri)
1402 .collect(ImmutableList.toImmutableList()))
1403 .containsExactly(testPath1.toString(), testPath2.toString());
1404 }
Klaus Aehlig17325a12016-09-30 15:45:27 +00001405}