blob: a8ecc550b45a882181e59926afe9a36ceaf58a74 [file] [log] [blame]
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +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
Klaus Aehlige52813b2016-08-02 10:06:07 +000016import static org.junit.Assert.assertEquals;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000017import static org.junit.Assert.assertFalse;
18import static org.junit.Assert.assertTrue;
19import static org.mockito.Mockito.when;
20
Dmitry Lomov15756522016-12-16 16:52:37 +000021import com.google.common.collect.ImmutableList;
Klaus Aehligd232d232016-04-13 09:51:25 +000022import com.google.common.collect.ImmutableSet;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000023import com.google.devtools.build.lib.actions.Action;
24import com.google.devtools.build.lib.actions.ActionCompletionEvent;
Klaus Aehlig0b26b422016-06-17 14:17:26 +000025import com.google.devtools.build.lib.actions.ActionExecutionMetadata;
janakr93e3eea2017-03-30 22:09:37 +000026import com.google.devtools.build.lib.actions.ActionLookupData;
Klaus Aehliga4c7d252016-05-20 10:44:21 +000027import com.google.devtools.build.lib.actions.ActionOwner;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000028import com.google.devtools.build.lib.actions.ActionStartedEvent;
Klaus Aehlig0b26b422016-06-17 14:17:26 +000029import com.google.devtools.build.lib.actions.ActionStatusMessage;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000030import com.google.devtools.build.lib.actions.Artifact;
31import com.google.devtools.build.lib.actions.Root;
Klaus Aehligd232d232016-04-13 09:51:25 +000032import com.google.devtools.build.lib.analysis.ConfiguredTarget;
Klaus Aehlig5c06b432017-03-01 18:00:39 +000033import com.google.devtools.build.lib.bazel.repository.downloader.DownloadProgressEvent;
Klaus Aehligd232d232016-04-13 09:51:25 +000034import com.google.devtools.build.lib.buildtool.buildevent.TestFilteringCompleteEvent;
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +000035import com.google.devtools.build.lib.cmdline.Label;
Dmitry Lomov15756522016-12-16 16:52:37 +000036import com.google.devtools.build.lib.packages.AspectDescriptor;
Klaus Aehligc6fd6bb2016-05-27 11:42:32 +000037import com.google.devtools.build.lib.skyframe.LoadingPhaseStartedEvent;
38import com.google.devtools.build.lib.skyframe.PackageProgressReceiver;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000039import com.google.devtools.build.lib.testutil.FoundationTestCase;
Klaus Aehliga63d9612016-04-04 12:15:23 +000040import com.google.devtools.build.lib.testutil.ManualClock;
Klaus Aehligc6fd6bb2016-05-27 11:42:32 +000041import com.google.devtools.build.lib.util.Pair;
Klaus Aehlig57c9dc92016-06-27 13:40:45 +000042import com.google.devtools.build.lib.util.io.LoggingTerminalWriter;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000043import com.google.devtools.build.lib.vfs.Path;
44import com.google.devtools.build.lib.vfs.PathFragment;
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +000045import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
Klaus Aehlige52813b2016-08-02 10:06:07 +000046import java.io.IOException;
Klaus Aehlig5c06b432017-03-01 18:00:39 +000047import java.net.URL;
Klaus Aehlige52813b2016-08-02 10:06:07 +000048import java.util.concurrent.TimeUnit;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000049import org.junit.Test;
50import org.junit.runner.RunWith;
51import org.junit.runners.JUnit4;
52import org.mockito.Mockito;
53
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000054/**
Klaus Aehligc23ba452016-04-06 12:16:39 +000055 * Tests {@link ExperimentalStateTracker}.
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000056 */
57@RunWith(JUnit4.class)
58public class ExperimentalStateTrackerTest extends FoundationTestCase {
59
60 private Action mockAction(String progressMessage, String primaryOutput) {
nharmatab4060b62017-04-04 17:11:39 +000061 Path path = outputBase.getRelative(PathFragment.create(primaryOutput));
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000062 Artifact artifact = new Artifact(path, Root.asSourceRoot(path));
63
64 Action action = Mockito.mock(Action.class);
65 when(action.getProgressMessage()).thenReturn(progressMessage);
66 when(action.getPrimaryOutput()).thenReturn(artifact);
67 return action;
68 }
69
Klaus Aehlig6d0876a2016-04-15 14:41:07 +000070 private int longestLine(String output) {
71 int maxLength = 0;
72 for (String line : output.split("\n")) {
73 maxLength = Math.max(maxLength, line.length());
74 }
75 return maxLength;
76 }
77
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000078 @Test
Klaus Aehligc6fd6bb2016-05-27 11:42:32 +000079 public void testLoadingActivity() throws IOException {
80 // During loading phase, state and activity, as reported by the PackageProgressReceiver,
81 // should be visible in the progress bar.
82 String state = "42 packages loaded";
83 String activity = "currently loading //src/foo/bar and 17 more";
84 PackageProgressReceiver progress = Mockito.mock(PackageProgressReceiver.class);
85 when(progress.progressState()).thenReturn(new Pair<String, String>(state, activity));
86
87 ManualClock clock = new ManualClock();
88 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
89
90 stateTracker.loadingStarted(new LoadingPhaseStartedEvent(progress));
91
92 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
93 stateTracker.writeProgressBar(terminalWriter);
94 String output = terminalWriter.getTranscript();
95
96 assertTrue(
97 "Output should indicate that we are in the loading phase, but was:\n" + output,
98 output.contains("Loading"));
99 assertTrue(
100 "Output should contain loading state '" + state + "', but was:\n" + output,
101 output.contains(state));
102 assertTrue(
103 "Output should contain loading state '" + activity + "', but was:\n" + output,
104 output.contains(activity));
105 }
106
107 @Test
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000108 public void testActionVisible() throws IOException {
109 // If there is only one action running, it should be visible
Klaus Aehligc0c88842016-04-11 12:07:38 +0000110 // somewhere in the progress bar, and also the short version thereof.
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000111
112 String message = "Building foo";
Klaus Aehliga63d9612016-04-04 12:15:23 +0000113 ManualClock clock = new ManualClock();
114 clock.advanceMillis(120000);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000115
Klaus Aehliga63d9612016-04-04 12:15:23 +0000116 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000117 stateTracker.actionStarted(new ActionStartedEvent(mockAction(message, "bar/foo"), 123456789));
Klaus Aehligc0c88842016-04-11 12:07:38 +0000118
Klaus Aehliged453e02016-04-15 11:29:05 +0000119 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000120 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000121 String output = terminalWriter.getTranscript();
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000122 assertTrue(
123 "Action message '" + message + "' should be present in output: " + output,
124 output.contains(message));
Klaus Aehligc0c88842016-04-11 12:07:38 +0000125
126 terminalWriter = new LoggingTerminalWriter();
127 stateTracker.writeProgressBar(terminalWriter, /* shortVersion=*/ true);
Klaus Aehliged453e02016-04-15 11:29:05 +0000128 output = terminalWriter.getTranscript();
Klaus Aehligc0c88842016-04-11 12:07:38 +0000129 assertTrue(
130 "Action message '" + message + "' should be present in short output: " + output,
131 output.contains(message));
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000132 }
133
134 @Test
135 public void testCompletedActionNotShown() throws IOException {
Klaus Aehligc0c88842016-04-11 12:07:38 +0000136 // Completed actions should not be reported in the progress bar, nor in the
137 // short progress bar.
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000138
139 String messageFast = "Running quick action";
140 String messageSlow = "Running slow action";
141
Klaus Aehliga63d9612016-04-04 12:15:23 +0000142 ManualClock clock = new ManualClock();
143 clock.advanceMillis(120000);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000144 Action fastAction = mockAction(messageFast, "foo/fast");
145 Action slowAction = mockAction(messageSlow, "bar/slow");
Klaus Aehliga63d9612016-04-04 12:15:23 +0000146 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000147 stateTracker.actionStarted(new ActionStartedEvent(fastAction, 123456789));
148 stateTracker.actionStarted(new ActionStartedEvent(slowAction, 123456999));
janakr93e3eea2017-03-30 22:09:37 +0000149 stateTracker.actionCompletion(
150 new ActionCompletionEvent(20, fastAction, Mockito.mock(ActionLookupData.class)));
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000151
Klaus Aehliged453e02016-04-15 11:29:05 +0000152 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000153 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000154 String output = terminalWriter.getTranscript();
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000155 assertFalse(
156 "Completed action '" + messageFast + "' should not be present in output: " + output,
157 output.contains(messageFast));
158 assertTrue(
159 "Only running action '" + messageSlow + "' should be present in output: " + output,
160 output.contains(messageSlow));
Klaus Aehligc0c88842016-04-11 12:07:38 +0000161
162 terminalWriter = new LoggingTerminalWriter();
163 stateTracker.writeProgressBar(terminalWriter, /* shortVersion=*/ true);
Klaus Aehliged453e02016-04-15 11:29:05 +0000164 output = terminalWriter.getTranscript();
Klaus Aehligc0c88842016-04-11 12:07:38 +0000165 assertFalse(
166 "Completed action '" + messageFast + "' should not be present in short output: " + output,
167 output.contains(messageFast));
168 assertTrue(
169 "Only running action '" + messageSlow + "' should be present in short output: " + output,
170 output.contains(messageSlow));
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000171 }
172
173 @Test
174 public void testOldestActionVisible() throws IOException {
Klaus Aehligc0c88842016-04-11 12:07:38 +0000175 // The earliest-started action is always visible somehow in the progress bar
176 // and its short version.
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000177
178 String messageOld = "Running the first-started action";
179
Klaus Aehliga63d9612016-04-04 12:15:23 +0000180 ManualClock clock = new ManualClock();
181 clock.advanceMillis(120000);
182 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000183 stateTracker.actionStarted(
184 new ActionStartedEvent(mockAction(messageOld, "bar/foo"), 123456789));
185 for (int i = 0; i < 30; i++) {
186 stateTracker.actionStarted(
187 new ActionStartedEvent(
188 mockAction("Other action " + i, "some/other/actions/number" + i), 123456790 + i));
189 }
190
Klaus Aehliged453e02016-04-15 11:29:05 +0000191 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000192 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000193 String output = terminalWriter.getTranscript();
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000194 assertTrue(
195 "Longest running action '" + messageOld + "' should be visible in output: " + output,
196 output.contains(messageOld));
Klaus Aehligc0c88842016-04-11 12:07:38 +0000197
Klaus Aehliged453e02016-04-15 11:29:05 +0000198 terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehligc0c88842016-04-11 12:07:38 +0000199 stateTracker.writeProgressBar(terminalWriter, /* shortVersion=*/ true);
Klaus Aehliged453e02016-04-15 11:29:05 +0000200 output = terminalWriter.getTranscript();
Klaus Aehligc0c88842016-04-11 12:07:38 +0000201 assertTrue(
202 "Longest running action '" + messageOld + "' should be visible in short output: " + output,
203 output.contains(messageOld));
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000204 }
Klaus Aehlige25642a2016-04-04 13:31:28 +0000205
206 @Test
Klaus Aehligcd211ee2016-06-21 08:44:15 +0000207 public void testSampleSize() throws IOException {
208 // Verify that the number of actions shown in the progress bar can be set as sample size.
209 ManualClock clock = new ManualClock();
210 clock.advanceMillis(TimeUnit.SECONDS.toMillis(123));
211 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
212 clock.advanceMillis(TimeUnit.SECONDS.toMillis(2));
213
214 // Start 10 actions (numbered 0 to 9).
215 for (int i = 0; i < 10; i++) {
216 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
217 Action action = mockAction("Performing action A" + i + ".", "action_A" + i + ".out");
218 stateTracker.actionStarted(new ActionStartedEvent(action, clock.nanoTime()));
219 }
220
221 // For various sample sizes verify the progress bar
222 for (int i = 1; i < 11; i++) {
223 stateTracker.setSampleSize(i);
224 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
225 stateTracker.writeProgressBar(terminalWriter);
226 String output = terminalWriter.getTranscript();
227 assertTrue(
228 "Action " + (i - 1) + " should still be shown in the output: '" + output,
229 output.contains("A" + (i - 1) + "."));
230 assertFalse(
231 "Action " + i + " should not be shown in the output: " + output,
232 output.contains("A" + i + "."));
233 if (i < 10) {
234 assertTrue("Ellipsis symbol should be shown in output: " + output, output.contains("..."));
235 } else {
236 assertFalse(
237 "Ellipsis symbol should not be shown in output: " + output, output.contains("..."));
238 }
239 }
240 }
241
242 @Test
Klaus Aehlige25642a2016-04-04 13:31:28 +0000243 public void testTimesShown() throws IOException {
244 // For sufficiently long running actions, the time that has passed since their start is shown.
Klaus Aehligc0c88842016-04-11 12:07:38 +0000245 // In the short version of the progress bar, this should be true at least for the oldest action.
Klaus Aehlige25642a2016-04-04 13:31:28 +0000246
247 ManualClock clock = new ManualClock();
248 clock.advanceMillis(TimeUnit.SECONDS.toMillis(123));
249 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
250 clock.advanceMillis(TimeUnit.SECONDS.toMillis(2));
251
252 stateTracker.actionStarted(
253 new ActionStartedEvent(mockAction("First action", "foo"), clock.nanoTime()));
254 clock.advanceMillis(TimeUnit.SECONDS.toMillis(7));
255 stateTracker.actionStarted(
256 new ActionStartedEvent(mockAction("Second action", "bar"), clock.nanoTime()));
257 clock.advanceMillis(TimeUnit.SECONDS.toMillis(20));
258
Klaus Aehliged453e02016-04-15 11:29:05 +0000259 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehlige25642a2016-04-04 13:31:28 +0000260 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000261 String output = terminalWriter.getTranscript();
Klaus Aehlige25642a2016-04-04 13:31:28 +0000262 assertTrue(
263 "Runtime of first action should be visible in output: " + output, output.contains("27s"));
264 assertTrue(
265 "Runtime of second action should be visible in output: " + output, output.contains("20s"));
Klaus Aehligc0c88842016-04-11 12:07:38 +0000266
Klaus Aehliged453e02016-04-15 11:29:05 +0000267 terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehligc0c88842016-04-11 12:07:38 +0000268 stateTracker.writeProgressBar(terminalWriter, /* shortVersion=*/ true);
Klaus Aehliged453e02016-04-15 11:29:05 +0000269 output = terminalWriter.getTranscript();
Klaus Aehligc0c88842016-04-11 12:07:38 +0000270 assertTrue(
271 "Runtime of first action should be visible in short output: " + output,
272 output.contains("27s"));
Klaus Aehlige25642a2016-04-04 13:31:28 +0000273 }
274
Klaus Aehlig2ce24d42016-04-04 15:54:58 +0000275 @Test
276 public void initialProgressBarTimeIndependent() {
277 ManualClock clock = new ManualClock();
278 clock.advanceMillis(TimeUnit.SECONDS.toMillis(123));
279 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
280
281 assertFalse(
282 "Initial progress status should be time independent",
283 stateTracker.progressBarTimeDependent());
284 }
285
286 @Test
287 public void runningActionTimeIndependent() {
288 ManualClock clock = new ManualClock();
289 clock.advanceMillis(TimeUnit.SECONDS.toMillis(123));
290 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
291 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
292 stateTracker.actionStarted(
293 new ActionStartedEvent(mockAction("Some action", "foo"), clock.nanoTime()));
294
295 assertTrue(
296 "Progress bar showing a running action should be time dependent",
297 stateTracker.progressBarTimeDependent());
298 }
Klaus Aehligd232d232016-04-13 09:51:25 +0000299
300 @Test
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000301 public void testCountVisible() throws Exception {
Klaus Aehligd232d232016-04-13 09:51:25 +0000302 // The test count should be visible in the status bar, as well as the short status bar
303 ManualClock clock = new ManualClock();
304 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
305 TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000306 Label labelA = Label.parseAbsolute("//foo/bar:baz");
Klaus Aehligd232d232016-04-13 09:51:25 +0000307 ConfiguredTarget targetA = Mockito.mock(ConfiguredTarget.class);
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000308 when(targetA.getLabel()).thenReturn(labelA);
Klaus Aehligd232d232016-04-13 09:51:25 +0000309 ConfiguredTarget targetB = Mockito.mock(ConfiguredTarget.class);
310 when(filteringComplete.getTestTargets()).thenReturn(ImmutableSet.of(targetA, targetB));
311 TestSummary testSummary = Mockito.mock(TestSummary.class);
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000312 when(testSummary.getTarget()).thenReturn(targetA);
313
Klaus Aehligd232d232016-04-13 09:51:25 +0000314 stateTracker.testFilteringComplete(filteringComplete);
315 stateTracker.testSummary(testSummary);
316
Klaus Aehliged453e02016-04-15 11:29:05 +0000317 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehligd232d232016-04-13 09:51:25 +0000318 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000319 String output = terminalWriter.getTranscript();
Klaus Aehligd232d232016-04-13 09:51:25 +0000320 assertTrue(
321 "Test count should be visible in output: " + output, output.contains(" 1 / 2 tests"));
322
Klaus Aehliged453e02016-04-15 11:29:05 +0000323 terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehligd232d232016-04-13 09:51:25 +0000324 stateTracker.writeProgressBar(terminalWriter, /* shortVersion=*/ true);
Klaus Aehliged453e02016-04-15 11:29:05 +0000325 output = terminalWriter.getTranscript();
Klaus Aehligd232d232016-04-13 09:51:25 +0000326 assertTrue(
327 "Test count should be visible in short output: " + output, output.contains(" 1 / 2 tests"));
328 }
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000329
330 @Test
331 public void testPassedVisible() throws Exception {
Klaus Aehlig07122cf2016-06-02 16:04:26 +0000332 // The last test should still be visible in the long status bar, and colored as ok if it passed.
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000333 ManualClock clock = new ManualClock();
334 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
335 TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
336 Label labelA = Label.parseAbsolute("//foo/bar:baz");
337 ConfiguredTarget targetA = Mockito.mock(ConfiguredTarget.class);
338 when(targetA.getLabel()).thenReturn(labelA);
339 ConfiguredTarget targetB = Mockito.mock(ConfiguredTarget.class);
340 when(filteringComplete.getTestTargets()).thenReturn(ImmutableSet.of(targetA, targetB));
341 TestSummary testSummary = Mockito.mock(TestSummary.class);
342 when(testSummary.getStatus()).thenReturn(BlazeTestStatus.PASSED);
343 when(testSummary.getTarget()).thenReturn(targetA);
344
345 stateTracker.testFilteringComplete(filteringComplete);
346 stateTracker.testSummary(testSummary);
347
Klaus Aehlig07122cf2016-06-02 16:04:26 +0000348 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter();
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000349 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000350 String output = terminalWriter.getTranscript();
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000351
Klaus Aehlig07122cf2016-06-02 16:04:26 +0000352 String expected = LoggingTerminalWriter.OK + labelA;
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000353 assertTrue(
Klaus Aehlig07122cf2016-06-02 16:04:26 +0000354 "Sequence '" + expected + "' should be present in colored progress bar: " + output,
355 output.contains(expected));
356 }
357
358 @Test
359 public void testFailedVisible() throws Exception {
360 // The last test should still be visible in the long status bar, and colored as fail if it
361 // did not pass.
362 ManualClock clock = new ManualClock();
363 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
364 TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
365 Label labelA = Label.parseAbsolute("//foo/bar:baz");
366 ConfiguredTarget targetA = Mockito.mock(ConfiguredTarget.class);
367 when(targetA.getLabel()).thenReturn(labelA);
368 ConfiguredTarget targetB = Mockito.mock(ConfiguredTarget.class);
369 when(filteringComplete.getTestTargets()).thenReturn(ImmutableSet.of(targetA, targetB));
370 TestSummary testSummary = Mockito.mock(TestSummary.class);
371 when(testSummary.getStatus()).thenReturn(BlazeTestStatus.FAILED);
372 when(testSummary.getTarget()).thenReturn(targetA);
373
374 stateTracker.testFilteringComplete(filteringComplete);
375 stateTracker.testSummary(testSummary);
376
377 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter();
378 stateTracker.writeProgressBar(terminalWriter);
379 String output = terminalWriter.getTranscript();
380
381 String expected = LoggingTerminalWriter.FAIL + labelA;
382 assertTrue(
383 "Sequence '" + expected + "' should be present in colored progress bar: " + output,
384 output.contains(expected));
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000385 }
Klaus Aehlig6d0876a2016-04-15 14:41:07 +0000386
Klaus Aehliga4c7d252016-05-20 10:44:21 +0000387 @Test
388 public void testSensibleShortening() throws Exception {
389 // Verify that in the typical case, we shorten the progress message by shortening
390 // the path implicit in it, that can also be extracted from the label. In particular,
391 // the parts
392 ManualClock clock = new ManualClock();
393 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock, 70);
394 Action action = mockAction(
395 "Building some/very/very/long/path/for/some/library/directory/foo.jar (42 source files)",
396 "/home/user/bazel/out/abcdef/some/very/very/long/path/for/some/library/directory/foo.jar");
397 Label label =
398 Label.parseAbsolute("//some/very/very/long/path/for/some/library/directory:libfoo");
Dmitry Lomov15756522016-12-16 16:52:37 +0000399 ActionOwner owner = ActionOwner.create(
400 label, ImmutableList.<AspectDescriptor>of(), null, null, null, "fedcba", null);
Klaus Aehliga4c7d252016-05-20 10:44:21 +0000401 when(action.getOwner()).thenReturn(owner);
402
403 clock.advanceMillis(TimeUnit.SECONDS.toMillis(3));
404 stateTracker.actionStarted(new ActionStartedEvent(action, clock.nanoTime()));
405 clock.advanceMillis(TimeUnit.SECONDS.toMillis(5));
406
407 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
408 stateTracker.writeProgressBar(terminalWriter);
409 String output = terminalWriter.getTranscript();
410
411 assertTrue(
412 "Progress bar should contain 'Building ', but was:\n" + output,
413 output.contains("Building "));
414 assertTrue(
415 "Progress bar should contain 'foo.jar (42 source files)', but was:\n" + output,
416 output.contains("foo.jar (42 source files)"));
417 }
418
Klaus Aehlig0b26b422016-06-17 14:17:26 +0000419 @Test
420 public void testActionStrategyVisible() throws Exception {
421 // verify that, if a strategy was reported for a shown action, it is visible
422 // in the progress bar.
423 String strategy = "verySpecialStrategy";
424 String primaryOutput = "some/path/to/a/file";
425
426 ManualClock clock = new ManualClock();
nharmatab4060b62017-04-04 17:11:39 +0000427 Path path = outputBase.getRelative(PathFragment.create(primaryOutput));
Klaus Aehlig0b26b422016-06-17 14:17:26 +0000428 Artifact artifact = new Artifact(path, Root.asSourceRoot(path));
429 ActionExecutionMetadata actionMetadata = Mockito.mock(ActionExecutionMetadata.class);
Ulf Adams17e20332017-03-07 15:51:39 +0000430 when(actionMetadata.getOwner()).thenReturn(Mockito.mock(ActionOwner.class));
Klaus Aehlig0b26b422016-06-17 14:17:26 +0000431 when(actionMetadata.getPrimaryOutput()).thenReturn(artifact);
432
433 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
434 stateTracker.actionStarted(
435 new ActionStartedEvent(mockAction("Some random action", primaryOutput), clock.nanoTime()));
436 stateTracker.actionStatusMessage(ActionStatusMessage.runningStrategy(actionMetadata, strategy));
437
438 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
439 stateTracker.writeProgressBar(terminalWriter);
440 String output = terminalWriter.getTranscript();
441
442 assertTrue(
443 "Output should mention strategy '" + strategy + "', but was: " + output,
444 output.contains(strategy));
445 }
446
Klaus Aehlig6d0876a2016-04-15 14:41:07 +0000447 private void doTestOutputLength(boolean withTest, int actions) throws Exception {
448 // If we target 70 characters, then there should be enough space to both,
449 // keep the line limit, and show the local part of the running actions and
450 // the passed test.
451 ManualClock clock = new ManualClock();
452 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock, 70);
453
454 Action foobuildAction = mockAction(
455 "Building //src/some/very/long/path/long/long/long/long/long/long/long/foo/foobuild.jar",
456 "//src/some/very/long/path/long/long/long/long/long/long/long/foo:foobuild");
457 Action bazbuildAction = mockAction(
458 "Building //src/some/very/long/path/long/long/long/long/long/long/long/baz/bazbuild.jar",
459 "//src/some/very/long/path/long/long/long/long/long/long/long/baz:bazbuild");
460
Klaus Aehlig0b26b422016-06-17 14:17:26 +0000461 Label bartestLabel =
462 Label.parseAbsolute(
463 "//src/another/very/long/long/path/long/long/long/long/long/long/long/long/bars:bartest");
Klaus Aehlig6d0876a2016-04-15 14:41:07 +0000464 ConfiguredTarget bartestTarget = Mockito.mock(ConfiguredTarget.class);
465 when(bartestTarget.getLabel()).thenReturn(bartestLabel);
466
467 TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
468 when(filteringComplete.getTestTargets()).thenReturn(ImmutableSet.of(bartestTarget));
469
470 TestSummary testSummary = Mockito.mock(TestSummary.class);
471 when(testSummary.getStatus()).thenReturn(BlazeTestStatus.PASSED);
472 when(testSummary.getTarget()).thenReturn(bartestTarget);
473
474 if (actions >= 1) {
475 stateTracker.actionStarted(new ActionStartedEvent(foobuildAction, 123456789));
476 }
477 if (actions >= 2) {
478 stateTracker.actionStarted(new ActionStartedEvent(bazbuildAction, 123456900));
479 }
480 if (withTest) {
481 stateTracker.testFilteringComplete(filteringComplete);
482 stateTracker.testSummary(testSummary);
483 }
484
485 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
486 stateTracker.writeProgressBar(terminalWriter);
487 String output = terminalWriter.getTranscript();
488
489 assertTrue(
490 "Only lines with at most 70 chars should be present in the output:\n" + output,
491 longestLine(output) <= 70);
492 if (actions >= 1) {
493 assertTrue(
494 "Running action 'foobuild' should be mentioned in output:\n" + output,
495 output.contains("foobuild"));
496 }
497 if (actions >= 2) {
498 assertTrue(
499 "Running action 'bazbuild' should be mentioned in output:\n" + output,
500 output.contains("bazbuild"));
501 }
502 if (withTest) {
503 assertTrue(
504 "Passed test ':bartest' should be mentioned in output:\n" + output,
505 output.contains(":bartest"));
506 }
507 }
508
509 @Test
510 public void testOutputLength() throws Exception {
511 for (int i = 0; i < 3; i++) {
512 doTestOutputLength(true, i);
513 doTestOutputLength(false, i);
514 }
515 }
Klaus Aehligc6d3ccc2016-05-24 12:58:09 +0000516
517 @Test
518 public void testAggregation() throws Exception {
519 // Assert that actions for the same test are aggregated so that an action afterwards
520 // is still shown.
521 ManualClock clock = new ManualClock();
522 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1234));
523 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock, 80);
524
525 Label labelFooTest = Label.parseAbsolute("//foo/bar:footest");
526 ConfiguredTarget targetFooTest = Mockito.mock(ConfiguredTarget.class);
527 when(targetFooTest.getLabel()).thenReturn(labelFooTest);
Carmi Grushko33aa3062016-11-11 02:45:29 +0000528 ActionOwner fooOwner =
Dmitry Lomov15756522016-12-16 16:52:37 +0000529 ActionOwner.create(labelFooTest,
530 ImmutableList.<AspectDescriptor>of(), null, null, null, "abcdef", null);
Klaus Aehligc6d3ccc2016-05-24 12:58:09 +0000531
532 Label labelBarTest = Label.parseAbsolute("//baz:bartest");
533 ConfiguredTarget targetBarTest = Mockito.mock(ConfiguredTarget.class);
534 when(targetBarTest.getLabel()).thenReturn(labelBarTest);
535 TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
536 when(filteringComplete.getTestTargets())
537 .thenReturn(ImmutableSet.of(targetFooTest, targetBarTest));
Carmi Grushko33aa3062016-11-11 02:45:29 +0000538 ActionOwner barOwner =
Dmitry Lomov15756522016-12-16 16:52:37 +0000539 ActionOwner.create(labelBarTest,
540 ImmutableList.<AspectDescriptor>of(), null, null, null, "fedcba", null);
Klaus Aehligc6d3ccc2016-05-24 12:58:09 +0000541
542 stateTracker.testFilteringComplete(filteringComplete);
543
544 // First produce 10 actions for footest...
545 for (int i = 0; i < 10; i++) {
546 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
547 Action action = mockAction("Testing foo, shard " + i, "testlog_foo_" + i);
548 when(action.getOwner()).thenReturn(fooOwner);
549 stateTracker.actionStarted(new ActionStartedEvent(action, clock.nanoTime()));
550 }
551 // ...then produce 10 actions for bartest...
552 for (int i = 0; i < 10; i++) {
553 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
554 Action action = mockAction("Testing bar, shard " + i, "testlog_bar_" + i);
555 when(action.getOwner()).thenReturn(barOwner);
556 stateTracker.actionStarted(new ActionStartedEvent(action, clock.nanoTime()));
557 }
558 // ...and finally a completely unrelated action
559 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
560 stateTracker.actionStarted(
561 new ActionStartedEvent(mockAction("Other action", "other/action"), clock.nanoTime()));
562 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
563
564 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
565 stateTracker.writeProgressBar(terminalWriter);
566 String output = terminalWriter.getTranscript();
567
568 assertTrue(
569 "Progress bar should contain ':footest', but was:\n" + output, output.contains(":footest"));
570 assertTrue(
571 "Progress bar should contain ':bartest', but was:\n" + output, output.contains(":bartest"));
572 assertTrue(
573 "Progress bar should contain 'Other action', but was:\n" + output,
574 output.contains("Other action"));
575 }
Klaus Aehlige52813b2016-08-02 10:06:07 +0000576
577
578 @Test
579 public void testSuffix() throws Exception {
580 assertEquals("bar", ExperimentalStateTracker.suffix("foobar", 3));
581 assertEquals("", ExperimentalStateTracker.suffix("foo", -2));
582 assertEquals("foobar", ExperimentalStateTracker.suffix("foobar", 200));
583 }
Klaus Aehlig5c06b432017-03-01 18:00:39 +0000584
585 @Test
586 public void testDownloadShown() throws Exception {
587 // Verify that, whenever a single download is running in loading face, it is shown in the status
588 // bar.
589 ManualClock clock = new ManualClock();
590 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1234));
591 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock, 80);
592
593 URL url = new URL("http://example.org/first/dep");
594
595 stateTracker.buildStarted(null);
596 stateTracker.downloadProgress(new DownloadProgressEvent(url));
597 clock.advanceMillis(TimeUnit.SECONDS.toMillis(6));
598
599 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
600 stateTracker.writeProgressBar(terminalWriter);
601 String output = terminalWriter.getTranscript();
602
603 assertTrue(
604 "Progress bar should contain '" + url.toString() + "', but was:\n" + output,
605 output.contains(url.toString()));
606 assertTrue("Progress bar should contain '6s', but was:\n" + output, output.contains("6s"));
607
608 // Progress on the pending download should be reported appropriately
609 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
610 stateTracker.downloadProgress(new DownloadProgressEvent(url, 256));
611
612 terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
613 stateTracker.writeProgressBar(terminalWriter);
614 output = terminalWriter.getTranscript();
615
616 assertTrue(
617 "Progress bar should contain '" + url.toString() + "', but was:\n" + output,
618 output.contains(url.toString()));
619 assertTrue("Progress bar should contain '7s', but was:\n" + output, output.contains("7s"));
620 assertTrue("Progress bar should contain '256', but was:\n" + output, output.contains("256"));
621
622 // After finishing the download, it should no longer be reported.
623 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
624 stateTracker.downloadProgress(new DownloadProgressEvent(url, 256, true));
625
626 terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
627 stateTracker.writeProgressBar(terminalWriter);
628 output = terminalWriter.getTranscript();
629
630 assertFalse(
631 "Progress bar should not contain url, but was:\n" + output, output.contains("example.org"));
632 }
633
634 @Test
635 public void testDownloadOutputLength() throws Exception {
636 // Verify that URLs are shortened in a reasonable way, if the terminal is not wide enough
637 // Also verify that the length is respected, even if only a download sample is shown.
638 ManualClock clock = new ManualClock();
639 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1234));
640 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock, 60);
641 URL url = new URL("http://example.org/some/really/very/very/long/path/filename.tar.gz");
642
643 stateTracker.buildStarted(null);
644 stateTracker.downloadProgress(new DownloadProgressEvent(url));
645 clock.advanceMillis(TimeUnit.SECONDS.toMillis(6));
646 for (int i = 0; i < 10; i++) {
647 stateTracker.downloadProgress(
648 new DownloadProgressEvent(
649 new URL(
650 "http://otherhost.example/another/also/length/path/to/another/download"
651 + i
652 + ".zip")));
653 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
654 }
655
656 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
657 stateTracker.writeProgressBar(terminalWriter);
658 String output = terminalWriter.getTranscript();
659
660 assertTrue(
661 "Only lines with at most 60 chars should be present in the output:\n" + output,
662 longestLine(output) <= 60);
663 assertTrue(
664 "Output still should contain the filename, but was:\n" + output,
665 output.contains("filename.tar.gz"));
666 assertTrue(
667 "Output still should contain the host name, but was:\n" + output,
668 output.contains("example.org"));
669 }
670
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000671}