blob: efec6b3f87791bcc84e1fd730622ab0331b0afde [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;
jhorvitzd72c3b2292020-10-20 10:29:38 -070018import static org.mockito.Mockito.mock;
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +020019import static org.mockito.Mockito.times;
20import static org.mockito.Mockito.verify;
21import static org.mockito.Mockito.when;
Klaus Aehlig17325a12016-09-30 15:45:27 +000022
philwo052e5f82021-01-19 10:47:41 -080023import com.google.common.base.Stopwatch;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040024import com.google.common.collect.ImmutableList;
Klaus Aehlig17325a12016-09-30 15:45:27 +000025import com.google.common.collect.ImmutableSet;
buchgr9e0308e2017-04-25 16:38:45 +020026import com.google.common.eventbus.Subscribe;
buchgr0b937432017-04-06 18:54:22 +000027import com.google.common.util.concurrent.Futures;
buchgr9e0308e2017-04-25 16:38:45 +020028import com.google.common.util.concurrent.ListenableFuture;
lberki86266232018-04-11 00:33:42 -070029import com.google.devtools.build.lib.actions.ActionEnvironment;
ruperts76de73b2018-03-02 16:10:43 -080030import com.google.devtools.build.lib.actions.ActionExecutedEvent;
31import com.google.devtools.build.lib.actions.ActionExecutedEvent.ErrorTiming;
32import com.google.devtools.build.lib.actions.ActionExecutionException;
Klaus Aehligee3e1922017-04-07 14:25:27 +000033import com.google.devtools.build.lib.actions.Artifact;
tomlu1cdcdf92018-01-16 11:07:51 -080034import com.google.devtools.build.lib.actions.ArtifactRoot;
felly9b91cb42019-06-04 09:35:21 -070035import com.google.devtools.build.lib.actions.CompletionContext;
Klaus Aehligee3e1922017-04-07 14:25:27 +000036import com.google.devtools.build.lib.actions.EventReportingArtifacts;
Googler17e28df2019-09-10 12:07:05 -070037import com.google.devtools.build.lib.actions.SpawnResult.MetadataLog;
ruperts76de73b2018-03-02 16:10:43 -080038import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040039import com.google.devtools.build.lib.analysis.BlazeDirectories;
janakr3b63a4e2017-09-14 09:55:40 +020040import com.google.devtools.build.lib.analysis.ServerDirectories;
jhorvitz33f76482021-10-28 10:13:26 -070041import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040042import com.google.devtools.build.lib.analysis.config.BuildOptions;
gregcee495e6b2019-04-30 14:07:06 -070043import com.google.devtools.build.lib.analysis.config.CoreOptions;
twigg44c30ac2021-12-08 15:57:11 -080044import com.google.devtools.build.lib.analysis.config.FragmentFactory;
45import com.google.devtools.build.lib.analysis.config.FragmentRegistry;
jhorvitzd72c3b2292020-10-20 10:29:38 -070046import com.google.devtools.build.lib.bugreport.BugReport;
buchgr9e0308e2017-04-25 16:38:45 +020047import com.google.devtools.build.lib.buildeventstream.AnnounceBuildEventTransportsEvent;
Klaus Aehligee3e1922017-04-07 14:25:27 +000048import com.google.devtools.build.lib.buildeventstream.ArtifactGroupNamer;
Klaus Aehlig17325a12016-09-30 15:45:27 +000049import com.google.devtools.build.lib.buildeventstream.BuildEvent;
felly75a422a2019-01-17 14:52:49 -080050import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
ulfjack26e586d2018-05-17 08:42:13 -070051import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
janakr3ca24682020-04-01 09:12:03 -070052import com.google.devtools.build.lib.buildeventstream.BuildEventIdUtil;
ulfjackfbf27562018-05-18 12:46:54 -070053import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
Klaus Aehligf75878d2016-11-21 13:41:16 +000054import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
jhorvitzd72c3b2292020-10-20 10:29:38 -070055import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.Aborted;
Googlerd990a0a2019-05-13 16:46:42 -070056import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.Aborted.AbortReason;
janakr3ca24682020-04-01 09:12:03 -070057import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId;
Klaus Aehligee3e1922017-04-07 14:25:27 +000058import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.NamedSetOfFilesId;
Googler17e28df2019-09-10 12:07:05 -070059import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.File;
Klaus Aehlig17325a12016-09-30 15:45:27 +000060import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
lberkid2630092018-11-22 09:12:34 -080061import com.google.devtools.build.lib.buildeventstream.BuildEventTransportClosedEvent;
Klaus Aehliga708a022017-07-11 12:54:40 +020062import com.google.devtools.build.lib.buildeventstream.BuildEventWithConfiguration;
Klaus Aehligf75878d2016-11-21 13:41:16 +000063import com.google.devtools.build.lib.buildeventstream.BuildEventWithOrderConstraint;
Klaus Aehlig17325a12016-09-30 15:45:27 +000064import com.google.devtools.build.lib.buildeventstream.GenericBuildEvent;
Klaus Aehligee3e1922017-04-07 14:25:27 +000065import com.google.devtools.build.lib.buildeventstream.PathConverter;
Klaus Aehlig17325a12016-09-30 15:45:27 +000066import com.google.devtools.build.lib.buildeventstream.ProgressEvent;
ruperts76de73b2018-03-02 16:10:43 -080067import com.google.devtools.build.lib.buildeventstream.transports.BuildEventStreamOptions;
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +000068import com.google.devtools.build.lib.buildtool.BuildResult;
Klaus Aehlig17325a12016-09-30 15:45:27 +000069import com.google.devtools.build.lib.buildtool.buildevent.BuildCompleteEvent;
Googlerd990a0a2019-05-13 16:46:42 -070070import com.google.devtools.build.lib.buildtool.buildevent.NoAnalyzeEvent;
jhorvitz6380c2892021-05-03 10:13:52 -070071import com.google.devtools.build.lib.cmdline.RepositoryName;
Klaus Aehligee3e1922017-04-07 14:25:27 +000072import com.google.devtools.build.lib.collect.nestedset.NestedSet;
73import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
adgarfcf9dd52021-03-09 09:04:47 -080074import com.google.devtools.build.lib.collect.nestedset.Order;
mschaller6bf7c512020-06-02 21:34:02 -070075import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
76import com.google.devtools.build.lib.server.FailureDetails.Spawn;
77import com.google.devtools.build.lib.server.FailureDetails.Spawn.Code;
Klaus Aehligee3e1922017-04-07 14:25:27 +000078import com.google.devtools.build.lib.testutil.FoundationTestCase;
mschaller854bb902020-03-03 10:56:14 -080079import com.google.devtools.build.lib.util.DetailedExitCode;
michajlod6d4ee22020-04-16 13:48:06 -070080import com.google.devtools.build.lib.util.Pair;
Klaus Aehligee3e1922017-04-07 14:25:27 +000081import com.google.devtools.build.lib.vfs.Path;
82import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080083import com.google.devtools.build.lib.vfs.Root;
Googler17e28df2019-09-10 12:07:05 -070084import com.google.devtools.build.lib.vfs.util.FileSystems;
ulfjackfbf27562018-05-18 12:46:54 -070085import com.google.devtools.common.options.Options;
Klaus Aehlig17325a12016-09-30 15:45:27 +000086import java.util.ArrayList;
Klaus Aehligf75878d2016-11-21 13:41:16 +000087import java.util.Collection;
buchgr9e0308e2017-04-25 16:38:45 +020088import java.util.Collections;
89import java.util.HashSet;
Klaus Aehlig17325a12016-09-30 15:45:27 +000090import java.util.List;
buchgr9e0308e2017-04-25 16:38:45 +020091import java.util.Set;
adgarfcf9dd52021-03-09 09:04:47 -080092import java.util.concurrent.CountDownLatch;
fellya4488a22019-04-03 13:05:47 -070093import java.util.concurrent.LinkedBlockingQueue;
94import java.util.concurrent.ThreadPoolExecutor;
lberkid2630092018-11-22 09:12:34 -080095import java.util.concurrent.TimeUnit;
fellya4488a22019-04-03 13:05:47 -070096import java.util.concurrent.atomic.AtomicInteger;
lberkid2630092018-11-22 09:12:34 -080097import java.util.concurrent.locks.LockSupport;
Googlerd990a0a2019-05-13 16:46:42 -070098import javax.annotation.Nullable;
fellya4488a22019-04-03 13:05:47 -070099import org.junit.Ignore;
Klaus Aehlig17325a12016-09-30 15:45:27 +0000100import org.junit.Test;
101import org.junit.runner.RunWith;
102import org.junit.runners.JUnit4;
103
104/** Tests {@link BuildEventStreamer}. */
105@RunWith(JUnit4.class)
jhorvitzd72c3b2292020-10-20 10:29:38 -0700106public final class BuildEventStreamerTest extends FoundationTestCase {
lpino0361ff62019-02-12 22:52:59 -0800107
jhorvitzd72c3b2292020-10-20 10:29:38 -0700108 private static final String OOM_MESSAGE = "Please build fewer targets.";
lpino0361ff62019-02-12 22:52:59 -0800109
jhorvitzd72c3b2292020-10-20 10:29:38 -0700110 private final CountingArtifactGroupNamer artifactGroupNamer = new CountingArtifactGroupNamer();
111 private final RecordingBuildEventTransport transport =
112 new RecordingBuildEventTransport(artifactGroupNamer);
113
114 private final BuildEventStreamer streamer =
115 new BuildEventStreamer.Builder()
116 .artifactGroupNamer(artifactGroupNamer)
117 .buildEventTransports(ImmutableSet.of(transport))
118 .besStreamOptions(new BuildEventStreamOptions())
119 .oomMessage(OOM_MESSAGE)
120 .build();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000121
Googler17e28df2019-09-10 12:07:05 -0700122 private static BuildEventContext getTestBuildEventContext(ArtifactGroupNamer artifactGroupNamer) {
123 return new BuildEventContext() {
124 @Override
125 public ArtifactGroupNamer artifactGroupNamer() {
126 return artifactGroupNamer;
127 }
128
129 @Override
130 public PathConverter pathConverter() {
jhorvitzd72c3b2292020-10-20 10:29:38 -0700131 return Path::toString;
Googler17e28df2019-09-10 12:07:05 -0700132 }
133
134 @Override
135 public BuildEventProtocolOptions getOptions() {
136 return Options.getDefaults(BuildEventProtocolOptions.class);
137 }
138 };
139 }
140
ruperts76de73b2018-03-02 16:10:43 -0800141 private static final ActionExecutedEvent SUCCESSFUL_ACTION_EXECUTED_EVENT =
142 new ActionExecutedEvent(
ulfjack5f312dd2018-10-02 04:58:53 -0700143 ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
ruperts76de73b2018-03-02 16:10:43 -0800144 new ActionsTestUtil.NullAction(),
jhorvitzd72c3b2292020-10-20 10:29:38 -0700145 /*exception=*/ null,
tomlud56a8062018-08-01 13:20:41 -0700146 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
jhorvitzd72c3b2292020-10-20 10:29:38 -0700147 /*stdout=*/ null,
148 /*stderr=*/ null,
149 /*actionMetadataLogs=*/ ImmutableList.of(),
felly3b050f62020-01-23 08:57:31 -0800150 ErrorTiming.NO_ERROR,
jhorvitzd72c3b2292020-10-20 10:29:38 -0700151 /*isInMemoryFs=*/ false);
ruperts76de73b2018-03-02 16:10:43 -0800152
jhorvitzd72c3b2292020-10-20 10:29:38 -0700153 private static final class RecordingBuildEventTransport implements BuildEventTransport {
Klaus Aehligee3e1922017-04-07 14:25:27 +0000154 private final List<BuildEvent> events = new ArrayList<>();
155 private final List<BuildEventStreamProtos.BuildEvent> eventsAsProtos = new ArrayList<>();
jhorvitzd72c3b2292020-10-20 10:29:38 -0700156 private final ArtifactGroupNamer artifactGroupNamer;
lpino0361ff62019-02-12 22:52:59 -0800157
jhorvitzd72c3b2292020-10-20 10:29:38 -0700158 RecordingBuildEventTransport(ArtifactGroupNamer namer) {
lpino0361ff62019-02-12 22:52:59 -0800159 this.artifactGroupNamer = namer;
160 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000161
162 @Override
buchgr9e0308e2017-04-25 16:38:45 +0200163 public String name() {
164 return this.getClass().getSimpleName();
165 }
166
167 @Override
felly6a8759f2019-07-09 11:27:03 -0700168 public boolean mayBeSlow() {
169 return false;
170 }
171
172 @Override
fellya4488a22019-04-03 13:05:47 -0700173 public synchronized void sendBuildEvent(BuildEvent event) {
Klaus Aehlig17325a12016-09-30 15:45:27 +0000174 events.add(event);
michajlo99725e12020-11-18 14:30:05 -0800175 try {
176 eventsAsProtos.add(event.asStreamProto(getTestBuildEventContext(this.artifactGroupNamer)));
177 } catch (InterruptedException e) {
178 Thread.currentThread().interrupt();
179 throw new IllegalStateException("interrupts not supported in test instance");
180 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000181 }
182
183 @Override
buchgr9e0308e2017-04-25 16:38:45 +0200184 public ListenableFuture<Void> close() {
buchgr0b937432017-04-06 18:54:22 +0000185 return Futures.immediateFuture(null);
186 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000187
felly75a422a2019-01-17 14:52:49 -0800188 @Override
189 public BuildEventArtifactUploader getUploader() {
190 throw new IllegalStateException();
191 }
192
Klaus Aehlig17325a12016-09-30 15:45:27 +0000193 List<BuildEvent> getEvents() {
194 return events;
195 }
Klaus Aehligee3e1922017-04-07 14:25:27 +0000196
197 List<BuildEventStreamProtos.BuildEvent> getEventProtos() {
198 return eventsAsProtos;
199 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000200 }
201
Klaus Aehligf75878d2016-11-21 13:41:16 +0000202 private static class GenericOrderEvent implements BuildEventWithOrderConstraint {
203 private final BuildEventId id;
204 private final Collection<BuildEventId> children;
205 private final Collection<BuildEventId> after;
206
207 GenericOrderEvent(
208 BuildEventId id, Collection<BuildEventId> children, Collection<BuildEventId> after) {
209 this.id = id;
210 this.children = children;
211 this.after = after;
212 }
213
214 GenericOrderEvent(BuildEventId id, Collection<BuildEventId> children) {
215 this(id, children, children);
216 }
217
218 @Override
219 public BuildEventId getEventId() {
220 return id;
221 }
222
223 @Override
224 public Collection<BuildEventId> getChildrenEvents() {
225 return children;
226 }
227
228 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700229 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehligf75878d2016-11-21 13:41:16 +0000230 return GenericBuildEvent.protoChaining(this).build();
231 }
232
233 @Override
234 public Collection<BuildEventId> postedAfter() {
235 return after;
236 }
237 }
238
jhorvitzd72c3b2292020-10-20 10:29:38 -0700239 private static final class GenericArtifactReportingEvent implements EventReportingArtifacts {
Klaus Aehligee3e1922017-04-07 14:25:27 +0000240 private final BuildEventId id;
241 private final Collection<BuildEventId> children;
242 private final Collection<NestedSet<Artifact>> artifacts;
243
244 GenericArtifactReportingEvent(
245 BuildEventId id,
246 Collection<BuildEventId> children,
247 Collection<NestedSet<Artifact>> artifacts) {
248 this.id = id;
249 this.children = children;
250 this.artifacts = artifacts;
251 }
252
253 GenericArtifactReportingEvent(BuildEventId id, Collection<NestedSet<Artifact>> artifacts) {
jhorvitzd72c3b2292020-10-20 10:29:38 -0700254 this(id, ImmutableSet.of(), artifacts);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000255 }
256
257 @Override
258 public BuildEventId getEventId() {
259 return id;
260 }
261
262 @Override
263 public Collection<BuildEventId> getChildrenEvents() {
264 return children;
265 }
266
267 @Override
tomlu04e92812018-08-02 11:49:08 -0700268 public ReportedArtifacts reportedArtifacts() {
felly9b91cb42019-06-04 09:35:21 -0700269 return new ReportedArtifacts(artifacts, CompletionContext.FAILED_COMPLETION_CTX);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000270 }
271
272 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700273 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehligee3e1922017-04-07 14:25:27 +0000274 BuildEventStreamProtos.NamedSetOfFiles.Builder builder =
275 BuildEventStreamProtos.NamedSetOfFiles.newBuilder();
276 for (NestedSet<Artifact> artifactset : artifacts) {
adonovan841ac612020-06-06 07:18:58 -0700277 builder.addFileSets(converters.artifactGroupNamer().apply(artifactset.toNode()));
Klaus Aehligee3e1922017-04-07 14:25:27 +0000278 }
279 return GenericBuildEvent.protoChaining(this).setNamedSetOfFiles(builder.build()).build();
280 }
281 }
282
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400283 private static class GenericConfigurationEvent implements BuildEventWithConfiguration {
284 private final BuildEventId id;
285 private final Collection<BuildEventId> children;
Klaus Aehliga708a022017-07-11 12:54:40 +0200286 private final Collection<BuildEvent> configurations;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400287
288 GenericConfigurationEvent(
Klaus Aehliga708a022017-07-11 12:54:40 +0200289 BuildEventId id, Collection<BuildEventId> children, Collection<BuildEvent> configurations) {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400290 this.id = id;
291 this.children = children;
292 this.configurations = configurations;
293 }
294
Klaus Aehliga708a022017-07-11 12:54:40 +0200295 GenericConfigurationEvent(BuildEventId id, BuildEvent configuration) {
jhorvitzd72c3b2292020-10-20 10:29:38 -0700296 this(id, ImmutableSet.of(), ImmutableSet.of(configuration));
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400297 }
298
299 @Override
300 public BuildEventId getEventId() {
301 return id;
302 }
303
304 @Override
305 public Collection<BuildEventId> getChildrenEvents() {
306 return children;
307 }
308
309 @Override
Klaus Aehliga708a022017-07-11 12:54:40 +0200310 public Collection<BuildEvent> getConfigurations() {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400311 return configurations;
312 }
313
314 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700315 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400316 return GenericBuildEvent.protoChaining(this).build();
317 }
318 }
319
Klaus Aehlig17325a12016-09-30 15:45:27 +0000320 private static BuildEventId testId(String opaque) {
janakr3ca24682020-04-01 09:12:03 -0700321 return BuildEventIdUtil.unknownBuildEventId(opaque);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000322 }
323
buchgr9e0308e2017-04-25 16:38:45 +0200324 private static class EventBusHandler {
325
326 Set<BuildEventTransport> transportSet;
327
328 @Subscribe
329 void transportsAnnounced(AnnounceBuildEventTransportsEvent evt) {
330 transportSet = Collections.synchronizedSet(new HashSet<>(evt.transports()));
331 }
lberkid2630092018-11-22 09:12:34 -0800332
333 @Subscribe
334 void transportClosed(BuildEventTransportClosedEvent evt) {
335 transportSet.remove(evt.transport());
336 }
buchgr9e0308e2017-04-25 16:38:45 +0200337 }
338
buchgr9e0308e2017-04-25 16:38:45 +0200339 @Test(timeout = 5000)
Klaus Aehlig17325a12016-09-30 15:45:27 +0000340 public void testSimpleStream() {
341 // Verify that a well-formed event is passed through and that completion of the
Klaus Aehligfb3c5722017-07-10 13:08:19 +0200342 // build clears the pending progress-update event. However, there is no guarantee
343 // on the order of the flushed events.
344 // Additionally, assert that the actual last event has the last_message flag set.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000345
buchgr9e0308e2017-04-25 16:38:45 +0200346 EventBusHandler handler = new EventBusHandler();
347 eventBus.register(handler);
lberkiaea56b32017-05-30 12:35:33 +0200348 assertThat(handler.transportSet).isNull();
buchgr9e0308e2017-04-25 16:38:45 +0200349
lpino5bec36c2019-03-21 09:50:52 -0700350 eventBus.post(new AnnounceBuildEventTransportsEvent(ImmutableSet.of(transport)));
351
Klaus Aehlig17325a12016-09-30 15:45:27 +0000352 BuildEvent startEvent =
353 new GenericBuildEvent(
janakr3ca24682020-04-01 09:12:03 -0700354 testId("Initial"),
355 ImmutableSet.of(
356 ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventIdUtil.buildFinished()));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000357
358 streamer.buildEvent(startEvent);
359
aehlig03d55f32017-10-26 11:45:35 +0200360 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000361 List<BuildEvent> afterFirstEvent = transport.getEvents();
362 assertThat(afterFirstEvent).hasSize(1);
lberkiaea56b32017-05-30 12:35:33 +0200363 assertThat(afterFirstEvent.get(0).getEventId()).isEqualTo(startEvent.getEventId());
364 assertThat(handler.transportSet).hasSize(1);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000365
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000366 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000367
aehlig03d55f32017-10-26 11:45:35 +0200368 assertThat(streamer.isClosed()).isTrue();
lpino5bec36c2019-03-21 09:50:52 -0700369 eventBus.post(new BuildEventTransportClosedEvent(transport));
370
Klaus Aehlig17325a12016-09-30 15:45:27 +0000371 List<BuildEvent> finalStream = transport.getEvents();
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000372 assertThat(finalStream).hasSize(3);
Klaus Aehligfb3c5722017-07-10 13:08:19 +0200373 assertThat(ImmutableSet.of(finalStream.get(1).getEventId(), finalStream.get(2).getEventId()))
374 .isEqualTo(
janakr3ca24682020-04-01 09:12:03 -0700375 ImmutableSet.of(
376 BuildEventIdUtil.buildFinished(), ProgressEvent.INITIAL_PROGRESS_UPDATE));
Klaus Aehligfb3c5722017-07-10 13:08:19 +0200377
378 // verify the "last_message" flag.
379 assertThat(transport.getEventProtos().get(0).getLastMessage()).isFalse();
380 assertThat(transport.getEventProtos().get(1).getLastMessage()).isFalse();
381 assertThat(transport.getEventProtos().get(2).getLastMessage()).isTrue();
lberkid2630092018-11-22 09:12:34 -0800382
383 while (!handler.transportSet.isEmpty()) {
384 LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
385 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000386 }
387
388 @Test
389 public void testChaining() {
390 // Verify that unannounced events are linked in with progress update events, assuming
391 // a correctly formed initial event.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000392 BuildEvent startEvent =
393 new GenericBuildEvent(
394 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
jhorvitzd72c3b2292020-10-20 10:29:38 -0700395 BuildEvent unexpectedEvent = new GenericBuildEvent(testId("unexpected"), ImmutableSet.of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000396
397 streamer.buildEvent(startEvent);
398 streamer.buildEvent(unexpectedEvent);
399
aehlig03d55f32017-10-26 11:45:35 +0200400 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000401 List<BuildEvent> eventsSeen = transport.getEvents();
402 assertThat(eventsSeen).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200403 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
404 assertThat(eventsSeen.get(2).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000405 BuildEvent linkEvent = eventsSeen.get(1);
lberkiaea56b32017-05-30 12:35:33 +0200406 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
407 assertWithMessage("Unexpected events should be linked")
408 .that(linkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
409 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000410 }
411
412 @Test
413 public void testBadInitialEvent() {
414 // Verify that, if the initial event does not announce the initial progress update event,
415 // the initial progress event is used instead to chain that event; in this way, new
416 // progress updates can always be chained in.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000417 BuildEvent unexpectedStartEvent =
jhorvitzd72c3b2292020-10-20 10:29:38 -0700418 new GenericBuildEvent(testId("unexpected start"), ImmutableSet.of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000419
420 streamer.buildEvent(unexpectedStartEvent);
421
422 List<BuildEvent> eventsSeen = transport.getEvents();
423 assertThat(eventsSeen).hasSize(2);
lberkiaea56b32017-05-30 12:35:33 +0200424 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(unexpectedStartEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000425 BuildEvent initial = eventsSeen.get(0);
lberkiaea56b32017-05-30 12:35:33 +0200426 assertThat(initial.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
427 assertWithMessage("Event should be linked")
428 .that(initial.getChildrenEvents().contains(unexpectedStartEvent.getEventId()))
429 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000430
431 // The initial event should also announce a new progress event; we test this
432 // by streaming another unannounced event.
433
jhorvitzd72c3b2292020-10-20 10:29:38 -0700434 BuildEvent unexpectedEvent = new GenericBuildEvent(testId("unexpected"), ImmutableSet.of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000435
436 streamer.buildEvent(unexpectedEvent);
aehlig03d55f32017-10-26 11:45:35 +0200437
438 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000439 List<BuildEvent> allEventsSeen = transport.getEvents();
440 assertThat(allEventsSeen).hasSize(4);
lberkiaea56b32017-05-30 12:35:33 +0200441 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000442 BuildEvent secondLinkEvent = allEventsSeen.get(2);
lberkiaea56b32017-05-30 12:35:33 +0200443 assertWithMessage("Progress should have been announced")
444 .that(initial.getChildrenEvents().contains(secondLinkEvent.getEventId()))
445 .isTrue();
446 assertWithMessage("Second event should be linked")
447 .that(secondLinkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
448 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000449 }
450
451 @Test
452 public void testReferPastEvent() {
453 // Verify that, if an event is refers to a previously done event, that duplicated
454 // late-referenced event is not expected again.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000455 BuildEvent startEvent =
456 new GenericBuildEvent(
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000457 testId("Initial"),
jhorvitzd72c3b2292020-10-20 10:29:38 -0700458 ImmutableSet.of(
janakr3ca24682020-04-01 09:12:03 -0700459 ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventIdUtil.buildFinished()));
jhorvitzd72c3b2292020-10-20 10:29:38 -0700460 BuildEvent earlyEvent = new GenericBuildEvent(testId("unexpected"), ImmutableSet.of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000461 BuildEvent lateReference =
462 new GenericBuildEvent(testId("late reference"), ImmutableSet.of(earlyEvent.getEventId()));
463
464 streamer.buildEvent(startEvent);
465 streamer.buildEvent(earlyEvent);
466 streamer.buildEvent(lateReference);
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000467 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000468
aehlig03d55f32017-10-26 11:45:35 +0200469 assertThat(streamer.isClosed()).isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000470 List<BuildEvent> eventsSeen = transport.getEvents();
471 int earlyEventCount = 0;
472 for (BuildEvent event : eventsSeen) {
473 if (event.getEventId().equals(earlyEvent.getEventId())) {
474 earlyEventCount++;
475 }
476 }
477 // The early event should be reported precisely once.
lberkiaea56b32017-05-30 12:35:33 +0200478 assertThat(earlyEventCount).isEqualTo(1);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000479 }
Klaus Aehligf75878d2016-11-21 13:41:16 +0000480
481 @Test
felly17594762019-02-07 15:24:32 -0800482 public void testReordering() {
Klaus Aehligf75878d2016-11-21 13:41:16 +0000483 // Verify that an event requiring to be posted after another one is indeed.
Klaus Aehligf75878d2016-11-21 13:41:16 +0000484 BuildEventId expectedId = testId("the target");
485 BuildEvent startEvent =
486 new GenericBuildEvent(
jhorvitzd72c3b2292020-10-20 10:29:38 -0700487 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, expectedId));
488 BuildEvent rootCause = new GenericBuildEvent(testId("failure event"), ImmutableSet.of());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000489 BuildEvent failedTarget =
jhorvitzd72c3b2292020-10-20 10:29:38 -0700490 new GenericOrderEvent(expectedId, ImmutableSet.of(rootCause.getEventId()));
Klaus Aehligf75878d2016-11-21 13:41:16 +0000491
492 streamer.buildEvent(startEvent);
493 streamer.buildEvent(failedTarget);
494 streamer.buildEvent(rootCause);
495
aehlig03d55f32017-10-26 11:45:35 +0200496 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligf75878d2016-11-21 13:41:16 +0000497 List<BuildEvent> allEventsSeen = transport.getEvents();
498 assertThat(allEventsSeen).hasSize(4);
lberkiaea56b32017-05-30 12:35:33 +0200499 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000500 BuildEvent linkEvent = allEventsSeen.get(1);
lberkiaea56b32017-05-30 12:35:33 +0200501 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
502 assertThat(allEventsSeen.get(2).getEventId()).isEqualTo(rootCause.getEventId());
503 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(failedTarget.getEventId());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000504 }
505
fellya4488a22019-04-03 13:05:47 -0700506 private static BuildEvent indexOrderedBuildEvent(int index, int afterIndex) {
507 return new GenericOrderEvent(
508 testId("Concurrent-" + index),
509 ImmutableList.of(),
510 afterIndex == -1
511 ? ImmutableList.of()
512 : ImmutableList.of(testId("Concurrent-" + afterIndex)));
513 }
514
515 @Test
516 public void testConcurrency() throws Exception {
517 // Verify that we can blast the BuildEventStreamer with many build events in parallel without
518 // violating internal consistency. The thread-safety under test is primarily sensitive to the
519 // pendingEvents field constructed when there are ordering constraints, so we make sure to
520 // include such ordering constraints in this test.
521 BuildEvent startEvent =
522 new GenericBuildEvent(
523 testId("Initial"),
janakr3ca24682020-04-01 09:12:03 -0700524 ImmutableSet.of(
525 ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventIdUtil.buildFinished()));
fellya4488a22019-04-03 13:05:47 -0700526 streamer.buildEvent(startEvent);
527
528 int numThreads = 12;
529 int numEventsPerThread = 10_000;
530 int totalEvents = numThreads * numEventsPerThread;
531 AtomicInteger idIndex = new AtomicInteger();
532 ThreadPoolExecutor pool =
533 new ThreadPoolExecutor(
534 numThreads,
535 numThreads,
536 /* keepAliveTime= */ 0,
537 TimeUnit.SECONDS,
538 /* workQueue= */ new LinkedBlockingQueue<>());
539
540 for (int i = 0; i < numThreads; i++) {
541 pool.execute(
542 () -> {
543 for (int j = 0; j < numEventsPerThread; j++) {
544 int index = idIndex.getAndIncrement();
545 // Arrange for half of the events to have an ordering constraint on the subsequent
546 // event. The ordering graph must avoid cycles.
547 int afterIndex = (index % 2 == 0) ? (index + 1) % totalEvents : -1;
548 streamer.buildEvent(indexOrderedBuildEvent(index, afterIndex));
549 }
550 });
551 }
552
553 pool.shutdown();
554 pool.awaitTermination(1, TimeUnit.DAYS);
555
556 BuildEventId lateId = testId("late event");
557 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId)));
558 assertThat(streamer.isClosed()).isFalse();
559 streamer.buildEvent(new GenericBuildEvent(lateId, ImmutableSet.of()));
560 assertThat(streamer.isClosed()).isTrue();
561
562 List<BuildEvent> eventsSeen = transport.getEvents();
563 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
564 assertThat(eventsSeen).hasSize(4 + totalEvents * 2);
565 }
566
567 // Re-enable this "test" for ad-hoc benchmarking of many concurrent build events.
568 @Ignore
569 public void concurrencyBenchmark() throws Exception {
570 long time = 0;
571 for (int iteration = 0; iteration < 3; iteration++) {
philwo052e5f82021-01-19 10:47:41 -0800572 Stopwatch watch = Stopwatch.createStarted();
fellya4488a22019-04-03 13:05:47 -0700573
fellya4488a22019-04-03 13:05:47 -0700574 BuildEvent startEvent =
575 new GenericBuildEvent(
576 testId("Initial"),
janakr3ca24682020-04-01 09:12:03 -0700577 ImmutableSet.of(
578 ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventIdUtil.buildFinished()));
fellya4488a22019-04-03 13:05:47 -0700579 streamer.buildEvent(startEvent);
580
581 int numThreads = 12;
582 int numEventsPerThread = 100_000;
583 int totalEvents = numThreads * numEventsPerThread;
584 AtomicInteger idIndex = new AtomicInteger();
585 ThreadPoolExecutor pool =
586 new ThreadPoolExecutor(
587 numThreads, numThreads, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
588
589 for (int i = 0; i < numThreads; i++) {
590 pool.execute(
591 () -> {
592 for (int j = 0; j < numEventsPerThread; j++) {
593 int index = idIndex.getAndIncrement();
594 // Arrange for half of the events to have an ordering constraint on the subsequent
595 // event. The ordering graph must avoid cycles.
596 int afterIndex = (index % 2 == 0) ? (index + 1) % totalEvents : -1;
597 streamer.buildEvent(indexOrderedBuildEvent(index, afterIndex));
598 }
599 });
600 }
601
602 pool.shutdown();
603 pool.awaitTermination(1, TimeUnit.DAYS);
604 watch.stop();
605
philwo052e5f82021-01-19 10:47:41 -0800606 time += watch.elapsed().toMillis();
fellya4488a22019-04-03 13:05:47 -0700607
608 BuildEventId lateId = testId("late event");
609 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId)));
610 assertThat(streamer.isClosed()).isFalse();
611 streamer.buildEvent(new GenericBuildEvent(lateId, ImmutableSet.of()));
612 assertThat(streamer.isClosed()).isTrue();
613 }
614
615 System.err.println();
616 System.err.println("=============================================================");
617 System.err.println("Concurrent performance of BEP build event processing: " + time + "ms");
618 System.err.println("=============================================================");
619 }
620
Klaus Aehligf75878d2016-11-21 13:41:16 +0000621 @Test
felly21c25822018-12-28 13:29:52 -0800622 public void testMissingPrerequisites() {
Klaus Aehligf75878d2016-11-21 13:41:16 +0000623 // Verify that an event where the prerequisite is never coming till the end of
624 // the build still gets posted, with the prerequisite aborted.
Klaus Aehligf75878d2016-11-21 13:41:16 +0000625 BuildEventId expectedId = testId("the target");
626 BuildEvent startEvent =
627 new GenericBuildEvent(
628 testId("Initial"),
jhorvitzd72c3b2292020-10-20 10:29:38 -0700629 ImmutableSet.of(
janakr3ca24682020-04-01 09:12:03 -0700630 ProgressEvent.INITIAL_PROGRESS_UPDATE,
631 expectedId,
632 BuildEventIdUtil.buildFinished()));
Klaus Aehligf75878d2016-11-21 13:41:16 +0000633 BuildEventId rootCauseId = testId("failure event");
jhorvitzd72c3b2292020-10-20 10:29:38 -0700634 BuildEvent failedTarget = new GenericOrderEvent(expectedId, ImmutableSet.of(rootCauseId));
Klaus Aehligf75878d2016-11-21 13:41:16 +0000635
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());
janakr3ca24682020-04-01 09:12:03 -0700644 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(BuildEventIdUtil.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(
jhorvitzd72c3b2292020-10-20 10:29:38 -0700658 initialId, ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, waitId));
Klaus Aehligceb0f622017-03-20 13:52:06 +0000659 BuildEvent waitingForStart =
jhorvitzd72c3b2292020-10-20 10:29:38 -0700660 new GenericOrderEvent(waitId, ImmutableSet.of(), ImmutableSet.of(initialId));
Klaus Aehligceb0f622017-03-20 13:52:06 +0000661
662 streamer.buildEvent(waitingForStart);
663 streamer.buildEvent(startEvent);
664
aehlig03d55f32017-10-26 11:45:35 +0200665 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligceb0f622017-03-20 13:52:06 +0000666 List<BuildEvent> allEventsSeen = transport.getEvents();
667 assertThat(allEventsSeen).hasSize(2);
lberkiaea56b32017-05-30 12:35:33 +0200668 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
669 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(waitingForStart.getEventId());
Klaus Aehligceb0f622017-03-20 13:52:06 +0000670 }
Klaus Aehligee3e1922017-04-07 14:25:27 +0000671
672 private Artifact makeArtifact(String pathString) {
673 Path path = outputBase.getRelative(PathFragment.create(pathString));
janakraea05602019-05-22 15:41:29 -0700674 return ActionsTestUtil.createArtifact(
675 ArtifactRoot.asSourceRoot(Root.fromPath(outputBase)), path);
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(
jhorvitzd72c3b2292020-10-20 10:29:38 -0700683 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
Klaus Aehligee3e1922017-04-07 14:25:27 +0000684
685 Artifact a = makeArtifact("path/a");
686 Artifact b = makeArtifact("path/b");
687 Artifact c = makeArtifact("path/c");
688 NestedSet<Artifact> innerGroup = NestedSetBuilder.<Artifact>stableOrder().add(a).add(b).build();
689 NestedSet<Artifact> group =
690 NestedSetBuilder.<Artifact>stableOrder().addTransitive(innerGroup).add(c).build();
691 BuildEvent reportingArtifacts =
692 new GenericArtifactReportingEvent(testId("reporting"), ImmutableSet.of(group));
693
694 streamer.buildEvent(startEvent);
695 streamer.buildEvent(reportingArtifacts);
696
aehlig03d55f32017-10-26 11:45:35 +0200697 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligee3e1922017-04-07 14:25:27 +0000698 List<BuildEvent> allEventsSeen = transport.getEvents();
699 List<BuildEventStreamProtos.BuildEvent> eventProtos = transport.getEventProtos();
lberkiaea56b32017-05-30 12:35:33 +0200700 assertThat(allEventsSeen).hasSize(7);
701 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
702 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000703 List<BuildEventStreamProtos.File> firstSetDirects =
704 eventProtos.get(2).getNamedSetOfFiles().getFilesList();
lberkiaea56b32017-05-30 12:35:33 +0200705 assertThat(firstSetDirects).hasSize(2);
706 assertThat(ImmutableSet.of(firstSetDirects.get(0).getUri(), firstSetDirects.get(1).getUri()))
707 .isEqualTo(ImmutableSet.of(a.getPath().toString(), b.getPath().toString()));
Klaus Aehligee3e1922017-04-07 14:25:27 +0000708 List<NamedSetOfFilesId> secondSetTransitives =
709 eventProtos.get(4).getNamedSetOfFiles().getFileSetsList();
lberkiaea56b32017-05-30 12:35:33 +0200710 assertThat(secondSetTransitives).hasSize(1);
711 assertThat(secondSetTransitives.get(0)).isEqualTo(eventProtos.get(2).getId().getNamedSet());
Klaus Aehligee3e1922017-04-07 14:25:27 +0000712 List<NamedSetOfFilesId> reportedArtifactSets =
713 eventProtos.get(6).getNamedSetOfFiles().getFileSetsList();
lberkiaea56b32017-05-30 12:35:33 +0200714 assertThat(reportedArtifactSets).hasSize(1);
715 assertThat(reportedArtifactSets.get(0)).isEqualTo(eventProtos.get(4).getId().getNamedSet());
Klaus Aehligee3e1922017-04-07 14:25:27 +0000716 }
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200717
718 @Test
adgarfcf9dd52021-03-09 09:04:47 -0800719 public void testArtifactSetsPrecedeReportingEvent() throws InterruptedException {
720 // Verify that reported artifacts appear as named_set_of_files before their ID is referenced by
721 // a reporting event.
722 BuildEvent startEvent =
723 new GenericBuildEvent(
724 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
725
726 // Prepare a dense NestedSet DAG with lots of shared references.
727 List<NestedSet<Artifact>> baseSets = new ArrayList<>();
728 baseSets.add(NestedSetBuilder.create(Order.STABLE_ORDER, makeArtifact("path/a")));
729 baseSets.add(NestedSetBuilder.create(Order.STABLE_ORDER, makeArtifact("path/b")));
730 baseSets.add(NestedSetBuilder.create(Order.STABLE_ORDER, makeArtifact("path/c")));
731 baseSets.add(NestedSetBuilder.create(Order.STABLE_ORDER, makeArtifact("path/d")));
732 List<NestedSet<Artifact>> depth2Sets = new ArrayList<>();
733 for (int i = 0; i < baseSets.size(); i++) {
734 depth2Sets.add(
735 NestedSetBuilder.<Artifact>stableOrder()
736 .addTransitive(baseSets.get(i))
737 .addTransitive(baseSets.get((i + 1) % baseSets.size()))
738 .build());
739 }
740 List<NestedSet<Artifact>> depth3Sets = new ArrayList<>();
741 for (int i = 0; i < depth2Sets.size(); i++) {
742 depth3Sets.add(
743 NestedSetBuilder.<Artifact>stableOrder()
744 .addTransitive(depth2Sets.get(i))
745 .addTransitive(depth2Sets.get((i + 1) % depth2Sets.size()))
746 .build());
747 }
748 List<NestedSet<Artifact>> depth4Sets = new ArrayList<>();
749 for (int i = 0; i < depth3Sets.size(); i++) {
750 depth4Sets.add(
751 NestedSetBuilder.<Artifact>stableOrder()
752 .addTransitive(depth3Sets.get(i))
753 .addTransitive(depth3Sets.get((i + 1) % depth3Sets.size()))
754 .build());
755 }
756 int numEvents = 20;
757 List<BuildEvent> eventsToPost = new ArrayList<>();
758 for (int i = 0; i < numEvents; i++) {
759 eventsToPost.add(
760 new GenericArtifactReportingEvent(
761 testId("reporting" + i), ImmutableSet.of(depth4Sets.get(i % depth4Sets.size()))));
762 }
763
764 streamer.buildEvent(startEvent);
765 // Publish `numEvents` different events that all report the same NamedSet of artifacts on
766 // `numEvents` different threads. Use latches to ensure:
767 //
768 // 1. all threads have started, before:
769 // 2. all threads send their event, before:
770 // 3. verifying the recorded events.
771 CountDownLatch readyToPublishLatch = new CountDownLatch(numEvents);
772 CountDownLatch startPublishingLatch = new CountDownLatch(1);
773 CountDownLatch donePublishingLatch = new CountDownLatch(numEvents);
774 for (int i = 0; i < numEvents; i++) {
775 int num = i;
776 new Thread(
777 () -> {
778 try {
779 BuildEvent reportingArtifacts = eventsToPost.get(num);
780 readyToPublishLatch.countDown();
781 startPublishingLatch.await();
782 streamer.buildEvent(reportingArtifacts);
783 } catch (InterruptedException e) {
784 throw new RuntimeException(e);
785 }
786 donePublishingLatch.countDown();
787 })
788 .start();
789 }
790 readyToPublishLatch.await();
791 startPublishingLatch.countDown();
792 donePublishingLatch.await();
793
794 assertThat(streamer.isClosed()).isFalse();
795 List<BuildEvent> allEventsSeen = transport.getEvents();
796 List<BuildEventStreamProtos.BuildEvent> eventProtos = transport.getEventProtos();
797 // Each GenericArtifactReportingEvent and NamedArtifactGroup event has a corresponding Progress
798 // event posted immediately before.
799 assertThat(allEventsSeen)
800 .hasSize(1 + ((numEvents + baseSets.size() + depth2Sets.size() + depth3Sets.size()) * 2));
801 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
802 // Verify that each named_set_of_files event is sent before all of the events that report that
803 // named_set.
804 Set<String> seenFileSets = new HashSet<>();
805 for (int i = 1; i < eventProtos.size(); i++) {
806 BuildEventStreamProtos.BuildEvent buildEvent = eventProtos.get(i);
807 if (buildEvent.getId().hasNamedSet()) {
808 // These are the separately-posted contents of reported artifacts.
809 seenFileSets.add(buildEvent.getId().getNamedSet().getId());
810 for (NamedSetOfFilesId nestedSetId : buildEvent.getNamedSetOfFiles().getFileSetsList()) {
811 assertThat(seenFileSets).contains(nestedSetId.getId());
812 }
813 } else if (buildEvent.getId().hasUnknown()) {
814 // These are the GenericArtifactReportingEvent that report artifacts.
815 for (NamedSetOfFilesId nestedSetId : buildEvent.getNamedSetOfFiles().getFileSetsList()) {
816 assertThat(seenFileSets).contains(nestedSetId.getId());
817 }
818 }
819 }
820 }
821
822 @Test
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200823 public void testStdoutReported() {
824 // Verify that stdout and stderr are reported in the build-event stream on progress
825 // events.
jhorvitzd72c3b2292020-10-20 10:29:38 -0700826 BuildEventStreamer.OutErrProvider outErr = mock(BuildEventStreamer.OutErrProvider.class);
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200827 String stdoutMsg = "Some text that was written to stdout.";
828 String stderrMsg = "The UI text that bazel wrote to stderr.";
michajlod6d4ee22020-04-16 13:48:06 -0700829 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg));
830 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg));
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200831 BuildEvent startEvent =
832 new GenericBuildEvent(
jhorvitzd72c3b2292020-10-20 10:29:38 -0700833 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
834 BuildEvent unexpectedEvent = new GenericBuildEvent(testId("unexpected"), ImmutableSet.of());
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200835
836 streamer.registerOutErrProvider(outErr);
837 streamer.buildEvent(startEvent);
838 streamer.buildEvent(unexpectedEvent);
839
aehlig03d55f32017-10-26 11:45:35 +0200840 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200841 List<BuildEvent> eventsSeen = transport.getEvents();
842 assertThat(eventsSeen).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200843 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
844 assertThat(eventsSeen.get(2).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200845 BuildEvent linkEvent = eventsSeen.get(1);
846 BuildEventStreamProtos.BuildEvent linkEventProto = transport.getEventProtos().get(1);
lberkiaea56b32017-05-30 12:35:33 +0200847 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
848 assertWithMessage("Unexpected events should be linked")
849 .that(linkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
850 .isTrue();
851 assertThat(linkEventProto.getProgress().getStdout()).isEqualTo(stdoutMsg);
852 assertThat(linkEventProto.getProgress().getStderr()).isEqualTo(stderrMsg);
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200853
854 // As there is only one progress event, the OutErrProvider should be queried
855 // only once for stdout and stderr.
856 verify(outErr, times(1)).getOut();
857 verify(outErr, times(1)).getErr();
858 }
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400859
860 @Test
felly21c25822018-12-28 13:29:52 -0800861 public void testStdoutReportedAfterCrash() {
862 // Verify that stdout and stderr are reported in the build-event stream on progress
863 // events.
jhorvitzd72c3b2292020-10-20 10:29:38 -0700864 BuildEventStreamer.OutErrProvider outErr = mock(BuildEventStreamer.OutErrProvider.class);
felly21c25822018-12-28 13:29:52 -0800865 String stdoutMsg = "Some text that was written to stdout.";
866 String stderrMsg = "The UI text that bazel wrote to stderr.";
michajlod6d4ee22020-04-16 13:48:06 -0700867 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg));
868 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg));
felly21c25822018-12-28 13:29:52 -0800869 BuildEvent startEvent =
870 new GenericBuildEvent(
jhorvitzd72c3b2292020-10-20 10:29:38 -0700871 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
felly21c25822018-12-28 13:29:52 -0800872
873 streamer.registerOutErrProvider(outErr);
874 streamer.buildEvent(startEvent);
jhorvitzd72c3b2292020-10-20 10:29:38 -0700875 // Simulate a crash with an abrupt call to #closeOnAbort().
876 streamer.closeOnAbort(AbortReason.INTERNAL);
felly21c25822018-12-28 13:29:52 -0800877 assertThat(streamer.isClosed()).isTrue();
878
879 List<BuildEvent> eventsSeen = transport.getEvents();
880 assertThat(eventsSeen).hasSize(2);
881 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
882 BuildEvent linkEvent = eventsSeen.get(1);
883 BuildEventStreamProtos.BuildEvent linkEventProto = transport.getEventProtos().get(1);
884 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
885 assertThat(linkEventProto.getProgress().getStdout()).isEqualTo(stdoutMsg);
886 assertThat(linkEventProto.getProgress().getStderr()).isEqualTo(stderrMsg);
887
888 // As there is only one progress event, the OutErrProvider should be queried
889 // only once for stdout and stderr.
890 verify(outErr, times(1)).getOut();
891 verify(outErr, times(1)).getErr();
892 }
893
michajlod6d4ee22020-04-16 13:48:06 -0700894 private static <T> ImmutableList<ImmutableList<Pair<T, T>>> consumeToLists(
895 Iterable<T> left, Iterable<T> right) {
896 ImmutableList.Builder<Pair<T, T>> consumerBuilder = ImmutableList.builder();
897 ImmutableList.Builder<Pair<T, T>> lastConsumerBuilder = ImmutableList.builder();
898
899 BuildEventStreamer.consumeAsPairs(
900 left,
901 right,
902 (t1, t2) -> consumerBuilder.add(Pair.of(t1, t2)),
903 (t1, t2) -> lastConsumerBuilder.add(Pair.of(t1, t2)));
904
905 return ImmutableList.of(consumerBuilder.build(), lastConsumerBuilder.build());
906 }
907
908 @Test
909 public void testConsumeAsPairs() {
910 assertThat(consumeToLists(ImmutableList.of(1, 2, 3), ImmutableList.of(4, 5, 6)))
911 .containsExactly(
912 ImmutableList.of(Pair.of(1, null), Pair.of(2, null), Pair.of(3, 4), Pair.of(null, 5)),
913 ImmutableList.of(Pair.of(null, 6)))
914 .inOrder();
915
916 assertThat(consumeToLists(ImmutableList.of(), ImmutableList.of()))
917 .containsExactly(ImmutableList.of(), ImmutableList.of(Pair.of(null, null)))
918 .inOrder();
919
920 assertThat(consumeToLists(ImmutableList.of(1), ImmutableList.of(2)))
921 .containsExactly(ImmutableList.of(), ImmutableList.of(Pair.of(1, 2)))
922 .inOrder();
923
924 assertThat(consumeToLists(ImmutableList.of(1), ImmutableList.of(2, 3)))
925 .containsExactly(ImmutableList.of(Pair.of(1, 2)), ImmutableList.of(Pair.of(null, 3)))
926 .inOrder();
927
928 assertThat(consumeToLists(ImmutableList.of(1, 2), ImmutableList.of()))
929 .containsExactly(ImmutableList.of(Pair.of(1, null)), ImmutableList.of(Pair.of(2, null)))
930 .inOrder();
931
932 assertThat(consumeToLists(ImmutableList.of(), ImmutableList.of(1)))
933 .containsExactly(ImmutableList.of(), ImmutableList.of(Pair.of(null, 1)))
934 .inOrder();
935 }
felly17594762019-02-07 15:24:32 -0800936
felly21c25822018-12-28 13:29:52 -0800937 @Test
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400938 public void testReportedConfigurations() throws Exception {
939 // Verify that configuration events are posted, but only once.
jhorvitzd72c3b2292020-10-20 10:29:38 -0700940 BuildOptions defaultBuildOptions = BuildOptions.of(ImmutableList.of(CoreOptions.class));
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400941 BuildEvent startEvent =
942 new GenericBuildEvent(
jhorvitzd72c3b2292020-10-20 10:29:38 -0700943 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
jhorvitz33f76482021-10-28 10:13:26 -0700944 BuildConfigurationValue configuration =
twigg44c30ac2021-12-08 15:57:11 -0800945 BuildConfigurationValue.create(
946 defaultBuildOptions,
Googler80ada0f2021-12-22 07:15:59 -0800947 RepositoryName.createFromValidStrippedName("workspace"),
twigg44c30ac2021-12-08 15:57:11 -0800948 /*siblingRepositoryLayout=*/ false,
janakr3b63a4e2017-09-14 09:55:40 +0200949 new BlazeDirectories(
Klaus Aehligc2499c42018-02-27 05:47:21 -0800950 new ServerDirectories(outputBase, outputBase, outputBase),
951 rootDirectory,
jhorvitz9ad5aed2021-04-23 14:32:33 -0700952 /*defaultSystemJavabase=*/ null,
Klaus Aehligc2499c42018-02-27 05:47:21 -0800953 "productName"),
twigg44c30ac2021-12-08 15:57:11 -0800954 new BuildConfigurationValue.GlobalStateProvider() {
955 @Override
956 public ActionEnvironment getActionEnvironment(BuildOptions buildOptions) {
957 return ActionEnvironment.EMPTY;
958 }
959
960 @Override
961 public FragmentRegistry getFragmentRegistry() {
962 return FragmentRegistry.create(
963 ImmutableList.of(), ImmutableList.of(), ImmutableList.of());
964 }
965
966 @Override
967 public ImmutableSet<String> getReservedActionMnemonics() {
968 return ImmutableSet.of();
969 }
970 },
971 new FragmentFactory());
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400972 BuildEvent firstWithConfiguration =
shahan50f99d52018-03-10 05:14:09 -0800973 new GenericConfigurationEvent(testId("first"), configuration.toBuildEvent());
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400974 BuildEvent secondWithConfiguration =
shahan50f99d52018-03-10 05:14:09 -0800975 new GenericConfigurationEvent(testId("second"), configuration.toBuildEvent());
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400976
977 streamer.buildEvent(startEvent);
978 streamer.buildEvent(firstWithConfiguration);
979 streamer.buildEvent(secondWithConfiguration);
980
aehlig03d55f32017-10-26 11:45:35 +0200981 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400982 List<BuildEvent> allEventsSeen = transport.getEvents();
lberkiaea56b32017-05-30 12:35:33 +0200983 assertThat(allEventsSeen).hasSize(7);
984 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
985 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
shahan50f99d52018-03-10 05:14:09 -0800986 assertThat(allEventsSeen.get(2)).isEqualTo(configuration.toBuildEvent());
janakr3ca24682020-04-01 09:12:03 -0700987 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(BuildEventIdUtil.progressId(1));
lberkiaea56b32017-05-30 12:35:33 +0200988 assertThat(allEventsSeen.get(4)).isEqualTo(firstWithConfiguration);
janakr3ca24682020-04-01 09:12:03 -0700989 assertThat(allEventsSeen.get(5).getEventId()).isEqualTo(BuildEventIdUtil.progressId(2));
lberkiaea56b32017-05-30 12:35:33 +0200990 assertThat(allEventsSeen.get(6)).isEqualTo(secondWithConfiguration);
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400991 }
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200992
993 @Test
jhorvitzd72c3b2292020-10-20 10:29:38 -0700994 public void testEarlyFlush() {
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200995 // Verify that the streamer can handle early calls to flush() and still correctly
996 // reports stdout and stderr in the build-event stream.
jhorvitzd72c3b2292020-10-20 10:29:38 -0700997 BuildEventStreamer.OutErrProvider outErr = mock(BuildEventStreamer.OutErrProvider.class);
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200998 String firstStdoutMsg = "Some text that was written to stdout.";
999 String firstStderrMsg = "The UI text that bazel wrote to stderr.";
1000 String secondStdoutMsg = "More text that was written to stdout, still before the start event.";
1001 String secondStderrMsg = "More text written to stderr, still before the start event.";
felly17594762019-02-07 15:24:32 -08001002 when(outErr.getOut())
michajlod6d4ee22020-04-16 13:48:06 -07001003 .thenReturn(ImmutableList.of(firstStdoutMsg))
1004 .thenReturn(ImmutableList.of(secondStdoutMsg));
felly17594762019-02-07 15:24:32 -08001005 when(outErr.getErr())
michajlod6d4ee22020-04-16 13:48:06 -07001006 .thenReturn(ImmutableList.of(firstStderrMsg))
1007 .thenReturn(ImmutableList.of(secondStderrMsg));
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001008 BuildEvent startEvent =
1009 new GenericBuildEvent(
jhorvitzd72c3b2292020-10-20 10:29:38 -07001010 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001011
1012 streamer.registerOutErrProvider(outErr);
1013 streamer.flush();
1014 streamer.flush();
1015 streamer.buildEvent(startEvent);
1016
aehlig03d55f32017-10-26 11:45:35 +02001017 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001018 List<BuildEvent> eventsSeen = transport.getEvents();
1019 assertThat(eventsSeen).hasSize(3);
1020 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
1021 BuildEvent progressEvent = eventsSeen.get(1);
1022 assertThat(progressEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
1023 BuildEventStreamProtos.BuildEvent progressEventProto = transport.getEventProtos().get(1);
1024 assertThat(progressEventProto.getProgress().getStdout()).isEqualTo(firstStdoutMsg);
1025 assertThat(progressEventProto.getProgress().getStderr()).isEqualTo(firstStderrMsg);
1026 BuildEventStreamProtos.BuildEvent secondProgressEventProto = transport.getEventProtos().get(2);
1027 assertThat(secondProgressEventProto.getProgress().getStdout()).isEqualTo(secondStdoutMsg);
1028 assertThat(secondProgressEventProto.getProgress().getStderr()).isEqualTo(secondStderrMsg);
1029
1030 // As there is only one progress event, the OutErrProvider should be queried
1031 // only once per flush() for stdout and stderr.
1032 verify(outErr, times(2)).getOut();
1033 verify(outErr, times(2)).getErr();
1034 }
1035
1036 @Test
jhorvitzd72c3b2292020-10-20 10:29:38 -07001037 public void testChunkedFlush() {
felly17594762019-02-07 15:24:32 -08001038 // Verify that the streamer calls to flush() that return multiple chunked buffers.
jhorvitzd72c3b2292020-10-20 10:29:38 -07001039 BuildEventStreamer.OutErrProvider outErr = mock(BuildEventStreamer.OutErrProvider.class);
felly17594762019-02-07 15:24:32 -08001040 String firstStdoutMsg = "Some text that was written to stdout.";
1041 String firstStderrMsg = "The UI text that bazel wrote to stderr.";
1042 String secondStdoutMsg = "More text that was written to stdout, still before the start event.";
1043 String secondStderrMsg = "More text written to stderr, still before the start event.";
michajlod6d4ee22020-04-16 13:48:06 -07001044 when(outErr.getOut()).thenReturn(ImmutableList.of(firstStdoutMsg, secondStdoutMsg));
1045 when(outErr.getErr()).thenReturn(ImmutableList.of(firstStderrMsg, secondStderrMsg));
felly17594762019-02-07 15:24:32 -08001046 BuildEvent startEvent =
1047 new GenericBuildEvent(
jhorvitzd72c3b2292020-10-20 10:29:38 -07001048 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
felly17594762019-02-07 15:24:32 -08001049
1050 streamer.registerOutErrProvider(outErr);
1051 streamer.buildEvent(startEvent);
1052 streamer.flush();
1053
1054 assertThat(streamer.isClosed()).isFalse();
1055 List<BuildEvent> eventsSeen = transport.getEvents();
1056 assertThat(eventsSeen).hasSize(4);
1057 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
1058
1059 // Expect to find 3 progress messages: (firstStdout, ""), (secondStdout, firstStderr),
1060 // ("", secondStdErr). Assuming UIs display stdout first, this maintains ordering.
1061 BuildEvent progressEvent = eventsSeen.get(1);
1062 assertThat(progressEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
1063 BuildEventStreamProtos.BuildEvent progressEventProto = transport.getEventProtos().get(1);
1064 assertThat(progressEventProto.getProgress().getStdout()).isEqualTo(firstStdoutMsg);
1065 assertThat(progressEventProto.getProgress().getStderr()).isEmpty();
1066
1067 BuildEventStreamProtos.BuildEvent secondProgressEventProto = transport.getEventProtos().get(2);
1068 assertThat(secondProgressEventProto.getProgress().getStdout()).isEqualTo(secondStdoutMsg);
1069 assertThat(secondProgressEventProto.getProgress().getStderr()).isEqualTo(firstStderrMsg);
1070
1071 BuildEventStreamProtos.BuildEvent thirdProgressEventProto = transport.getEventProtos().get(3);
1072 assertThat(thirdProgressEventProto.getProgress().getStdout()).isEmpty();
1073 assertThat(thirdProgressEventProto.getProgress().getStderr()).isEqualTo(secondStderrMsg);
1074
1075 // The OutErrProvider should be queried only once per flush().
1076 verify(outErr, times(1)).getOut();
1077 verify(outErr, times(1)).getErr();
1078 }
1079
1080 @Test
jhorvitzd72c3b2292020-10-20 10:29:38 -07001081 public void testNoopFlush() {
Klaus Aehlig28221ff2018-01-11 04:28:00 -08001082 // Verify that the streamer ignores a flush, if neither stream produces any output.
jhorvitzd72c3b2292020-10-20 10:29:38 -07001083 BuildEventStreamer.OutErrProvider outErr = mock(BuildEventStreamer.OutErrProvider.class);
Klaus Aehlig28221ff2018-01-11 04:28:00 -08001084 String stdoutMsg = "Some text that was written to stdout.";
1085 String stderrMsg = "The UI text that bazel wrote to stderr.";
michajlod6d4ee22020-04-16 13:48:06 -07001086 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg)).thenReturn(ImmutableList.of());
1087 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg)).thenReturn(ImmutableList.of());
Klaus Aehlig28221ff2018-01-11 04:28:00 -08001088 BuildEvent startEvent =
1089 new GenericBuildEvent(
jhorvitzd72c3b2292020-10-20 10:29:38 -07001090 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
Klaus Aehlig28221ff2018-01-11 04:28:00 -08001091
1092 streamer.registerOutErrProvider(outErr);
1093 streamer.buildEvent(startEvent);
1094 assertThat(transport.getEvents()).hasSize(1);
1095 streamer.flush(); // Output, so a new progress event has to be added
1096 assertThat(transport.getEvents()).hasSize(2);
1097 streamer.flush(); // No further output, so no additional event should be generated.
1098 assertThat(transport.getEvents()).hasSize(2);
1099
1100 assertThat(transport.getEvents().get(0)).isEqualTo(startEvent);
1101 assertThat(transport.getEventProtos().get(1).getProgress().getStdout()).isEqualTo(stdoutMsg);
1102 assertThat(transport.getEventProtos().get(1).getProgress().getStderr()).isEqualTo(stderrMsg);
1103 }
1104
1105 @Test
jhorvitzd72c3b2292020-10-20 10:29:38 -07001106 public void testEarlyFlushBadInitialEvent() {
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001107 // Verify that an early flush works correctly with an unusual start event.
1108 // In this case, we expect 3 events in the stream, in that order:
jingwen68c57f02018-11-21 16:17:17 -08001109 // - an artificial progress event as initial event, to properly link in
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001110 // all events
1111 // - the unusal first event we have seen, and
1112 // - a progress event reporting the flushed messages.
jhorvitzd72c3b2292020-10-20 10:29:38 -07001113 BuildEventStreamer.OutErrProvider outErr = mock(BuildEventStreamer.OutErrProvider.class);
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001114 String stdoutMsg = "Some text that was written to stdout.";
1115 String stderrMsg = "The UI text that bazel wrote to stderr.";
michajlod6d4ee22020-04-16 13:48:06 -07001116 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg));
1117 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg));
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001118
1119 BuildEvent unexpectedStartEvent =
jhorvitzd72c3b2292020-10-20 10:29:38 -07001120 new GenericBuildEvent(testId("unexpected start"), ImmutableSet.of());
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001121
1122 streamer.registerOutErrProvider(outErr);
1123 streamer.flush();
1124 streamer.buildEvent(unexpectedStartEvent);
1125
aehlig03d55f32017-10-26 11:45:35 +02001126 assertThat(streamer.isClosed()).isFalse();
1127
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001128 List<BuildEvent> eventsSeen = transport.getEvents();
1129 assertThat(eventsSeen).hasSize(3);
1130
1131 BuildEvent initial = eventsSeen.get(0);
1132 assertThat(initial.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
1133 BuildEventStreamProtos.BuildEvent initialProto = transport.getEventProtos().get(0);
1134 assertThat(initialProto.getProgress().getStdout()).isEmpty();
1135 assertThat(initialProto.getProgress().getStderr()).isEmpty();
1136
1137 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(unexpectedStartEvent.getEventId());
1138 assertWithMessage("Unexpected event should be linked")
1139 .that(initial.getChildrenEvents().contains(unexpectedStartEvent.getEventId()))
1140 .isTrue();
1141
1142 BuildEventStreamProtos.BuildEvent progressProto = transport.getEventProtos().get(2);
1143 assertThat(progressProto.getProgress().getStdout()).isEqualTo(stdoutMsg);
1144 assertThat(progressProto.getProgress().getStderr()).isEqualTo(stderrMsg);
1145 assertWithMessage("flushed progress should be linked")
1146 .that(initial.getChildrenEvents().contains(eventsSeen.get(2).getEventId()))
1147 .isTrue();
1148
1149 verify(outErr, times(1)).getOut();
1150 verify(outErr, times(1)).getErr();
1151 }
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001152
1153 @Test
jhorvitzd72c3b2292020-10-20 10:29:38 -07001154 public void testEarlyAbort() {
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001155 // For a build that is aborted before a build-started event is generated,
1156 // we still expect that, if a build-started event is forced by some order
1157 // constraint (e.g., CommandLine wants to come after build started), then
1158 // that gets sorted to the beginning.
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001159 BuildEvent orderEvent =
1160 new GenericOrderEvent(
1161 testId("event depending on start"),
1162 ImmutableList.of(),
janakr3ca24682020-04-01 09:12:03 -07001163 ImmutableList.of(BuildEventIdUtil.buildStartedId()));
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001164
1165 streamer.buildEvent(orderEvent);
1166 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
1167
aehlig03d55f32017-10-26 11:45:35 +02001168 assertThat(streamer.isClosed()).isTrue();
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001169 List<BuildEvent> eventsSeen = transport.getEvents();
1170 assertThat(eventsSeen).hasSize(4);
janakr3ca24682020-04-01 09:12:03 -07001171 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(BuildEventIdUtil.buildStartedId());
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001172 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(orderEvent.getEventId());
1173 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
1174 .isEqualTo(
janakr3ca24682020-04-01 09:12:03 -07001175 ImmutableSet.of(
1176 BuildEventIdUtil.buildFinished(), ProgressEvent.INITIAL_PROGRESS_UPDATE));
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001177 assertThat(transport.getEventProtos().get(3).getLastMessage()).isTrue();
1178 }
aehlig03d55f32017-10-26 11:45:35 +02001179
1180 @Test
jhorvitzd72c3b2292020-10-20 10:29:38 -07001181 public void testFinalEventsLate() {
aehlig03d55f32017-10-26 11:45:35 +02001182 // Verify that we correctly handle late events (i.e., events coming only after the
1183 // BuildCompleteEvent) that are sent to the streamer after the BuildCompleteEvent.
aehlig03d55f32017-10-26 11:45:35 +02001184 BuildEvent startEvent =
1185 new GenericBuildEvent(
1186 testId("Initial"),
janakr3ca24682020-04-01 09:12:03 -07001187 ImmutableSet.of(
1188 ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventIdUtil.buildFinished()));
aehlig03d55f32017-10-26 11:45:35 +02001189 BuildEventId lateId = testId("late event");
1190 BuildEvent finishedEvent = new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId));
1191
1192 streamer.buildEvent(startEvent);
1193 streamer.buildEvent(finishedEvent);
1194 assertThat(streamer.isClosed()).isFalse();
1195 streamer.buildEvent(new GenericBuildEvent(lateId, ImmutableSet.of()));
1196 assertThat(streamer.isClosed()).isTrue();
1197
1198 List<BuildEvent> eventsSeen = transport.getEvents();
1199 assertThat(eventsSeen).hasSize(4);
1200 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
janakr3ca24682020-04-01 09:12:03 -07001201 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(BuildEventIdUtil.buildFinished());
aehlig03d55f32017-10-26 11:45:35 +02001202 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
1203 .isEqualTo(ImmutableSet.of(lateId, ProgressEvent.INITIAL_PROGRESS_UPDATE));
1204 }
1205
1206 @Test
jhorvitzd72c3b2292020-10-20 10:29:38 -07001207 public void testFinalEventsEarly() {
aehlig03d55f32017-10-26 11:45:35 +02001208 // Verify that we correctly handle late events (i.e., events coming only after the
1209 // BuildCompleteEvent) that are sent to the streamer before the BuildCompleteEvent,
1210 // but with an order constraint to come afterwards.
aehlig03d55f32017-10-26 11:45:35 +02001211 BuildEvent startEvent =
1212 new GenericBuildEvent(
1213 testId("Initial"),
janakr3ca24682020-04-01 09:12:03 -07001214 ImmutableSet.of(
1215 ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventIdUtil.buildFinished()));
aehlig03d55f32017-10-26 11:45:35 +02001216 BuildEventId lateId = testId("late event");
1217 BuildEvent finishedEvent = new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId));
1218
1219 streamer.buildEvent(startEvent);
1220 streamer.buildEvent(
1221 new GenericOrderEvent(
janakr3ca24682020-04-01 09:12:03 -07001222 lateId, ImmutableSet.of(), ImmutableList.of(BuildEventIdUtil.buildFinished())));
aehlig03d55f32017-10-26 11:45:35 +02001223 streamer.buildEvent(finishedEvent);
1224 assertThat(streamer.isClosed()).isTrue();
1225
1226 List<BuildEvent> eventsSeen = transport.getEvents();
1227 assertThat(eventsSeen).hasSize(4);
1228 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
janakr3ca24682020-04-01 09:12:03 -07001229 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(BuildEventIdUtil.buildFinished());
aehlig03d55f32017-10-26 11:45:35 +02001230 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
1231 .isEqualTo(ImmutableSet.of(lateId, ProgressEvent.INITIAL_PROGRESS_UPDATE));
1232 }
ruperts76de73b2018-03-02 16:10:43 -08001233
1234 @Test
1235 public void testSuccessfulActionsAreNotPublishedByDefault() {
1236 EventBusHandler handler = new EventBusHandler();
1237 eventBus.register(handler);
ruperts76de73b2018-03-02 16:10:43 -08001238 ActionExecutedEvent failedActionExecutedEvent =
1239 new ActionExecutedEvent(
ulfjack5f312dd2018-10-02 04:58:53 -07001240 ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
ruperts76de73b2018-03-02 16:10:43 -08001241 new ActionsTestUtil.NullAction(),
mschaller29020182020-06-10 23:16:07 -07001242 new ActionExecutionException(
1243 "Exception",
1244 /* action= */ null,
1245 /* catastrophe= */ false,
1246 DetailedExitCode.of(
1247 FailureDetail.newBuilder()
1248 .setSpawn(Spawn.newBuilder().setCode(Code.EXECUTION_DENIED))
1249 .build())),
tomlud56a8062018-08-01 13:20:41 -07001250 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
jhorvitzd72c3b2292020-10-20 10:29:38 -07001251 /*stdout=*/ null,
1252 /*stderr=*/ null,
1253 /*actionMetadataLogs=*/ ImmutableList.of(),
felly3b050f62020-01-23 08:57:31 -08001254 ErrorTiming.BEFORE_EXECUTION,
jhorvitzd72c3b2292020-10-20 10:29:38 -07001255 /*isInMemoryFs=*/ false);
ruperts76de73b2018-03-02 16:10:43 -08001256
1257 streamer.buildEvent(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1258 streamer.buildEvent(failedActionExecutedEvent);
1259
1260 List<BuildEvent> transportedEvents = transport.getEvents();
1261
1262 assertThat(transportedEvents).doesNotContain(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1263 assertThat(transportedEvents).contains(failedActionExecutedEvent);
1264 }
1265
1266 @Test
1267 public void testSuccessfulActionsCanBePublished() {
1268 EventBusHandler handler = new EventBusHandler();
1269 eventBus.register(handler);
1270
1271 BuildEventStreamOptions options = new BuildEventStreamOptions();
1272 options.publishAllActions = true;
1273
ruperts76de73b2018-03-02 16:10:43 -08001274 BuildEventStreamer streamer =
lpino2bf89062019-02-21 03:24:49 -08001275 new BuildEventStreamer.Builder()
1276 .artifactGroupNamer(artifactGroupNamer)
1277 .besStreamOptions(options)
lpino2bf89062019-02-21 03:24:49 -08001278 .buildEventTransports(ImmutableSet.of(transport))
1279 .build();
ruperts76de73b2018-03-02 16:10:43 -08001280
1281 ActionExecutedEvent failedActionExecutedEvent =
1282 new ActionExecutedEvent(
ulfjack5f312dd2018-10-02 04:58:53 -07001283 ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
ruperts76de73b2018-03-02 16:10:43 -08001284 new ActionsTestUtil.NullAction(),
mschaller29020182020-06-10 23:16:07 -07001285 new ActionExecutionException(
1286 "Exception",
1287 /* action= */ null,
1288 /* catastrophe= */ false,
1289 DetailedExitCode.of(
1290 FailureDetail.newBuilder()
1291 .setSpawn(Spawn.newBuilder().setCode(Code.EXECUTION_DENIED))
1292 .build())),
tomlud56a8062018-08-01 13:20:41 -07001293 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
ruperts76de73b2018-03-02 16:10:43 -08001294 /* stdout= */ null,
1295 /* stderr= */ null,
Googler17e28df2019-09-10 12:07:05 -07001296 /* actionMetadataLogs= */ ImmutableList.of(),
felly3b050f62020-01-23 08:57:31 -08001297 ErrorTiming.BEFORE_EXECUTION,
1298 /* isInMemoryFs= */ false);
ruperts76de73b2018-03-02 16:10:43 -08001299
1300 streamer.buildEvent(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1301 streamer.buildEvent(failedActionExecutedEvent);
1302
1303 List<BuildEvent> transportedEvents = transport.getEvents();
1304
1305 assertThat(transportedEvents).contains(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1306 assertThat(transportedEvents).contains(failedActionExecutedEvent);
1307 }
Googlerd990a0a2019-05-13 16:46:42 -07001308
1309 @Test
1310 public void testBuildIncomplete() {
1311 BuildEventId buildEventId = testId("abort_expected");
1312 BuildEvent startEvent =
1313 new GenericBuildEvent(
janakr3ca24682020-04-01 09:12:03 -07001314 BuildEventIdUtil.buildStartedId(),
Googlerd990a0a2019-05-13 16:46:42 -07001315 ImmutableSet.of(
janakr3ca24682020-04-01 09:12:03 -07001316 buildEventId,
1317 ProgressEvent.INITIAL_PROGRESS_UPDATE,
1318 BuildEventIdUtil.buildFinished()));
Googlerd990a0a2019-05-13 16:46:42 -07001319 BuildCompleteEvent buildCompleteEvent =
mschaller6bf7c512020-06-02 21:34:02 -07001320 buildCompleteEvent(createGenericDetailedExitCode(), true, null, false);
Googlerd990a0a2019-05-13 16:46:42 -07001321
1322 streamer.buildEvent(startEvent);
1323 streamer.buildEvent(buildCompleteEvent);
1324 streamer.close();
1325
1326 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1327 assertThat(aborted).isNotNull();
jhorvitzd72c3b2292020-10-20 10:29:38 -07001328 assertThat(aborted.hasAborted()).isTrue();
Googlerd990a0a2019-05-13 16:46:42 -07001329 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INCOMPLETE);
1330 assertThat(aborted.getAborted().getDescription()).isEmpty();
1331 }
1332
1333 @Test
1334 public void testBuildCrash() {
1335 BuildEventId buildEventId = testId("abort_expected");
1336 BuildEvent startEvent =
1337 new GenericBuildEvent(
janakr3ca24682020-04-01 09:12:03 -07001338 BuildEventIdUtil.buildStartedId(),
Googlerd990a0a2019-05-13 16:46:42 -07001339 ImmutableSet.of(
janakr3ca24682020-04-01 09:12:03 -07001340 buildEventId,
1341 ProgressEvent.INITIAL_PROGRESS_UPDATE,
1342 BuildEventIdUtil.buildFinished()));
Googlerd990a0a2019-05-13 16:46:42 -07001343 BuildCompleteEvent buildCompleteEvent =
mschaller6bf7c512020-06-02 21:34:02 -07001344 buildCompleteEvent(createGenericDetailedExitCode(), true, new RuntimeException(), false);
Googlerd990a0a2019-05-13 16:46:42 -07001345
1346 streamer.buildEvent(startEvent);
1347 streamer.buildEvent(buildCompleteEvent);
1348 streamer.close();
1349
1350 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1351 assertThat(aborted).isNotNull();
jhorvitzd72c3b2292020-10-20 10:29:38 -07001352 assertThat(aborted.hasAborted()).isTrue();
Googlerd990a0a2019-05-13 16:46:42 -07001353 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INTERNAL);
1354 assertThat(aborted.getAborted().getDescription()).isEmpty();
1355 }
1356
1357 @Test
1358 public void testBuildCatastrophe() {
1359 BuildEventId buildEventId = testId("abort_expected");
1360 BuildEvent startEvent =
1361 new GenericBuildEvent(
janakr3ca24682020-04-01 09:12:03 -07001362 BuildEventIdUtil.buildStartedId(),
Googlerd990a0a2019-05-13 16:46:42 -07001363 ImmutableSet.of(
janakr3ca24682020-04-01 09:12:03 -07001364 buildEventId,
1365 ProgressEvent.INITIAL_PROGRESS_UPDATE,
1366 BuildEventIdUtil.buildFinished()));
Googlerd990a0a2019-05-13 16:46:42 -07001367 BuildCompleteEvent buildCompleteEvent =
mschaller6bf7c512020-06-02 21:34:02 -07001368 buildCompleteEvent(createGenericDetailedExitCode(), true, null, true);
Googlerd990a0a2019-05-13 16:46:42 -07001369
1370 streamer.buildEvent(startEvent);
1371 streamer.buildEvent(buildCompleteEvent);
1372 streamer.close();
1373
1374 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1375 assertThat(aborted).isNotNull();
jhorvitzd72c3b2292020-10-20 10:29:38 -07001376 assertThat(aborted.hasAborted()).isTrue();
Googlerd990a0a2019-05-13 16:46:42 -07001377 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INTERNAL);
1378 assertThat(aborted.getAborted().getDescription()).isEmpty();
1379 }
1380
1381 @Test
1382 public void testStreamAbortedWithTimeout() {
1383 BuildEventId buildEventId = testId("abort_expected");
1384 BuildEvent startEvent =
1385 new GenericBuildEvent(
janakr3ca24682020-04-01 09:12:03 -07001386 BuildEventIdUtil.buildStartedId(),
Googlerd990a0a2019-05-13 16:46:42 -07001387 ImmutableSet.of(
janakr3ca24682020-04-01 09:12:03 -07001388 buildEventId,
1389 ProgressEvent.INITIAL_PROGRESS_UPDATE,
1390 BuildEventIdUtil.buildFinished()));
Googlerd990a0a2019-05-13 16:46:42 -07001391
1392 streamer.buildEvent(startEvent);
jhorvitzd72c3b2292020-10-20 10:29:38 -07001393 streamer.closeOnAbort(AbortReason.TIME_OUT);
Googlerd990a0a2019-05-13 16:46:42 -07001394
1395 BuildEventStreamProtos.BuildEvent aborted0 = getBepEvent(buildEventId);
1396 assertThat(aborted0).isNotNull();
jhorvitzd72c3b2292020-10-20 10:29:38 -07001397 assertThat(aborted0.hasAborted()).isTrue();
Googlerd990a0a2019-05-13 16:46:42 -07001398 assertThat(aborted0.getAborted().getReason()).isEqualTo(AbortReason.TIME_OUT);
1399 assertThat(aborted0.getAborted().getDescription()).isEmpty();
1400
janakr3ca24682020-04-01 09:12:03 -07001401 BuildEventStreamProtos.BuildEvent aborted1 = getBepEvent(BuildEventIdUtil.buildFinished());
Googlerd990a0a2019-05-13 16:46:42 -07001402 assertThat(aborted1).isNotNull();
jhorvitzd72c3b2292020-10-20 10:29:38 -07001403 assertThat(aborted1.hasAborted()).isTrue();
Googlerd990a0a2019-05-13 16:46:42 -07001404 assertThat(aborted1.getAborted().getReason()).isEqualTo(AbortReason.TIME_OUT);
1405 assertThat(aborted1.getAborted().getDescription()).isEmpty();
1406 }
1407
1408 @Test
1409 public void testBuildFailureMultipleReasons() {
1410 BuildEventId buildEventId = testId("abort_expected");
1411 BuildEvent startEvent =
1412 new GenericBuildEvent(
janakr3ca24682020-04-01 09:12:03 -07001413 BuildEventIdUtil.buildStartedId(),
Googlerd990a0a2019-05-13 16:46:42 -07001414 ImmutableSet.of(
janakr3ca24682020-04-01 09:12:03 -07001415 buildEventId,
1416 ProgressEvent.INITIAL_PROGRESS_UPDATE,
1417 BuildEventIdUtil.buildFinished()));
Googlerd990a0a2019-05-13 16:46:42 -07001418 BuildCompleteEvent buildCompleteEvent =
mschaller6bf7c512020-06-02 21:34:02 -07001419 buildCompleteEvent(createGenericDetailedExitCode(), false, new RuntimeException(), false);
Googlerd990a0a2019-05-13 16:46:42 -07001420
1421 streamer.buildEvent(startEvent);
1422 streamer.noAnalyze(new NoAnalyzeEvent());
1423 streamer.buildEvent(buildCompleteEvent);
1424 streamer.close();
1425
1426 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1427 assertThat(aborted).isNotNull();
jhorvitzd72c3b2292020-10-20 10:29:38 -07001428 assertThat(aborted.hasAborted()).isTrue();
Googlerd990a0a2019-05-13 16:46:42 -07001429 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INTERNAL);
1430 assertThat(aborted.getAborted().getDescription())
1431 .isEqualTo("Multiple abort reasons reported: [NO_ANALYZE, INTERNAL]");
1432 }
1433
jhorvitzd72c3b2292020-10-20 10:29:38 -07001434 @Test
1435 public void nonOomAbortReason_doesNotIncludeOomMessage() {
1436 BuildEventId buildEventId = testId("abort_expected");
1437 BuildEvent startEvent =
1438 new GenericBuildEvent(
1439 BuildEventIdUtil.buildStartedId(),
1440 ImmutableSet.of(
1441 buildEventId,
1442 ProgressEvent.INITIAL_PROGRESS_UPDATE,
1443 BuildEventIdUtil.buildFinished()));
1444
1445 streamer.buildEvent(startEvent);
1446 streamer.closeOnAbort(AbortReason.INTERNAL);
1447
1448 assertThat(getBepEvent(buildEventId).getAborted())
1449 .isEqualTo(Aborted.newBuilder().setReason(AbortReason.INTERNAL).build());
1450 }
1451
1452 @Test
1453 public void oomAbortReason_includesOomMessage() {
1454 BuildEventId buildEventId = testId("abort_expected");
1455 BuildEvent startEvent =
1456 new GenericBuildEvent(
1457 BuildEventIdUtil.buildStartedId(),
1458 ImmutableSet.of(
1459 buildEventId,
1460 ProgressEvent.INITIAL_PROGRESS_UPDATE,
1461 BuildEventIdUtil.buildFinished()));
1462
1463 streamer.buildEvent(startEvent);
1464 streamer.closeOnAbort(AbortReason.OUT_OF_MEMORY);
1465
1466 assertThat(getBepEvent(buildEventId).getAborted())
1467 .isEqualTo(
1468 Aborted.newBuilder()
1469 .setReason(AbortReason.OUT_OF_MEMORY)
1470 .setDescription(BugReport.constructOomExitMessage(OOM_MESSAGE))
1471 .build());
1472 }
1473
Googlerd990a0a2019-05-13 16:46:42 -07001474 @Nullable
1475 private BuildEventStreamProtos.BuildEvent getBepEvent(BuildEventId buildEventId) {
1476 return transport.getEventProtos().stream()
janakr3ca24682020-04-01 09:12:03 -07001477 .filter(e -> e.getId().equals(buildEventId))
Googlerd990a0a2019-05-13 16:46:42 -07001478 .findFirst()
1479 .orElse(null);
1480 }
1481
jhorvitzd72c3b2292020-10-20 10:29:38 -07001482 private static BuildCompleteEvent buildCompleteEvent(
mschaller6bf7c512020-06-02 21:34:02 -07001483 DetailedExitCode detailedExitCode,
1484 boolean stopOnFailure,
1485 Throwable crash,
1486 boolean catastrophe) {
Googlerd990a0a2019-05-13 16:46:42 -07001487 BuildResult result = new BuildResult(0);
mschaller6bf7c512020-06-02 21:34:02 -07001488 result.setDetailedExitCode(detailedExitCode);
Googlerd990a0a2019-05-13 16:46:42 -07001489 result.setStopOnFirstFailure(stopOnFailure);
1490 if (catastrophe) {
1491 result.setCatastrophe();
1492 }
1493 if (crash != null) {
1494 result.setUnhandledThrowable(crash);
1495 }
1496 return new BuildCompleteEvent(result);
1497 }
Googler17e28df2019-09-10 12:07:05 -07001498
1499 private static ActionExecutedEvent createActionExecutedEventWithLogs(
1500 ImmutableList<MetadataLog> metadataLogs) {
1501 return new ActionExecutedEvent(
1502 ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
1503 new ActionsTestUtil.NullAction(),
1504 /* exception= */ null,
1505 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
1506 /* stdout= */ null,
1507 /* stderr= */ null,
1508 metadataLogs,
felly3b050f62020-01-23 08:57:31 -08001509 ErrorTiming.NO_ERROR,
1510 /* isInMemoryFs= */ false);
Googler17e28df2019-09-10 12:07:05 -07001511 }
1512
1513 @Test
1514 public void testActionExecutedEventLogsConstructor() {
1515 String metadataLogName = "action_metadata";
1516 Path testPath1 = FileSystems.getJavaIoFileSystem().getPath("/path/to/logs-1");
1517 Path testPath2 = FileSystems.getJavaIoFileSystem().getPath("/path/to/logs-2");
1518 MetadataLog testMetadataLog1 = new MetadataLog(metadataLogName, testPath1);
1519 MetadataLog testMetadataLog2 = new MetadataLog(metadataLogName, testPath2);
1520
1521 ActionExecutedEvent withLogsEvent =
1522 createActionExecutedEventWithLogs(ImmutableList.of(testMetadataLog1, testMetadataLog2));
Googler17e28df2019-09-10 12:07:05 -07001523
1524 assertWithMessage("List parameter should return list of log path values")
1525 .that(withLogsEvent.getActionMetadataLogs())
1526 .containsExactly(testMetadataLog1, testMetadataLog2);
1527 assertWithMessage("Null logs parameter should return empty list.")
jhorvitzd72c3b2292020-10-20 10:29:38 -07001528 .that(SUCCESSFUL_ACTION_EXECUTED_EVENT.getActionMetadataLogs())
Googler17e28df2019-09-10 12:07:05 -07001529 .isEmpty();
1530 }
1531
1532 @Test
michajlo99725e12020-11-18 14:30:05 -08001533 public void testActionExcutedEventProtoLogs() throws Exception {
Googler17e28df2019-09-10 12:07:05 -07001534 String metadataLogName = "action_metadata";
1535 Path testPath1 = FileSystems.getJavaIoFileSystem().getPath("/path/to/logs-1");
1536 Path testPath2 = FileSystems.getJavaIoFileSystem().getPath("/path/to/logs-2");
1537
1538 ActionExecutedEvent withLogsEvent =
1539 createActionExecutedEventWithLogs(
1540 ImmutableList.of(
1541 new MetadataLog(metadataLogName, testPath1),
1542 new MetadataLog(metadataLogName, testPath2)));
Googler17e28df2019-09-10 12:07:05 -07001543
1544 BuildEventStreamProtos.BuildEvent buildEventLogs =
1545 withLogsEvent.asStreamProto(getTestBuildEventContext(artifactGroupNamer));
1546 BuildEventStreamProtos.BuildEvent buildEventNoLogs =
jhorvitzd72c3b2292020-10-20 10:29:38 -07001547 SUCCESSFUL_ACTION_EXECUTED_EVENT.asStreamProto(
1548 getTestBuildEventContext(artifactGroupNamer));
Googler17e28df2019-09-10 12:07:05 -07001549
1550 assertWithMessage("With logs build event action should contain 2 log files")
1551 .that(buildEventLogs.getAction().getActionMetadataLogsCount())
1552 .isEqualTo(2);
1553 assertWithMessage("No logs build event action should contain 0 log files")
1554 .that(buildEventNoLogs.getAction().getActionMetadataLogsCount())
1555 .isEqualTo(0);
1556 assertWithMessage("Event action should contains the two paths")
1557 .that(
1558 buildEventLogs.getAction().getActionMetadataLogsList().stream()
1559 .map(File::getUri)
1560 .collect(ImmutableList.toImmutableList()))
1561 .containsExactly(testPath1.toString(), testPath2.toString());
1562 }
mschaller6bf7c512020-06-02 21:34:02 -07001563
1564 private static DetailedExitCode createGenericDetailedExitCode() {
1565 return DetailedExitCode.of(
1566 FailureDetail.newBuilder()
1567 .setSpawn(Spawn.newBuilder().setCode(Code.NON_ZERO_EXIT))
1568 .build());
1569 }
Klaus Aehlig17325a12016-09-30 15:45:27 +00001570}