blob: 5954f43aa808449134dbba296fc6ba9f75236aab [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;
Klaus Aehliga4c7d252016-05-20 10:44:21 +000026import com.google.devtools.build.lib.actions.ActionOwner;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000027import com.google.devtools.build.lib.actions.ActionStartedEvent;
Klaus Aehlig0b26b422016-06-17 14:17:26 +000028import com.google.devtools.build.lib.actions.ActionStatusMessage;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000029import com.google.devtools.build.lib.actions.Artifact;
30import com.google.devtools.build.lib.actions.Root;
Klaus Aehligd232d232016-04-13 09:51:25 +000031import com.google.devtools.build.lib.analysis.ConfiguredTarget;
Klaus Aehlig5c06b432017-03-01 18:00:39 +000032import com.google.devtools.build.lib.bazel.repository.downloader.DownloadProgressEvent;
Klaus Aehligd232d232016-04-13 09:51:25 +000033import com.google.devtools.build.lib.buildtool.buildevent.TestFilteringCompleteEvent;
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +000034import com.google.devtools.build.lib.cmdline.Label;
Dmitry Lomov15756522016-12-16 16:52:37 +000035import com.google.devtools.build.lib.packages.AspectDescriptor;
Klaus Aehligc6fd6bb2016-05-27 11:42:32 +000036import com.google.devtools.build.lib.skyframe.LoadingPhaseStartedEvent;
37import com.google.devtools.build.lib.skyframe.PackageProgressReceiver;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000038import com.google.devtools.build.lib.testutil.FoundationTestCase;
Klaus Aehliga63d9612016-04-04 12:15:23 +000039import com.google.devtools.build.lib.testutil.ManualClock;
Klaus Aehligc6fd6bb2016-05-27 11:42:32 +000040import com.google.devtools.build.lib.util.Pair;
Klaus Aehlig57c9dc92016-06-27 13:40:45 +000041import com.google.devtools.build.lib.util.io.LoggingTerminalWriter;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000042import com.google.devtools.build.lib.vfs.Path;
43import com.google.devtools.build.lib.vfs.PathFragment;
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +000044import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
Klaus Aehlige52813b2016-08-02 10:06:07 +000045import java.io.IOException;
Klaus Aehlig5c06b432017-03-01 18:00:39 +000046import java.net.URL;
Klaus Aehlige52813b2016-08-02 10:06:07 +000047import java.util.concurrent.TimeUnit;
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000048import org.junit.Test;
49import org.junit.runner.RunWith;
50import org.junit.runners.JUnit4;
51import org.mockito.Mockito;
52
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000053/**
Klaus Aehligc23ba452016-04-06 12:16:39 +000054 * Tests {@link ExperimentalStateTracker}.
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000055 */
56@RunWith(JUnit4.class)
57public class ExperimentalStateTrackerTest extends FoundationTestCase {
58
59 private Action mockAction(String progressMessage, String primaryOutput) {
60 Path path = outputBase.getRelative(new PathFragment(primaryOutput));
61 Artifact artifact = new Artifact(path, Root.asSourceRoot(path));
62
63 Action action = Mockito.mock(Action.class);
64 when(action.getProgressMessage()).thenReturn(progressMessage);
65 when(action.getPrimaryOutput()).thenReturn(artifact);
66 return action;
67 }
68
Klaus Aehlig6d0876a2016-04-15 14:41:07 +000069 private int longestLine(String output) {
70 int maxLength = 0;
71 for (String line : output.split("\n")) {
72 maxLength = Math.max(maxLength, line.length());
73 }
74 return maxLength;
75 }
76
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +000077 @Test
Klaus Aehligc6fd6bb2016-05-27 11:42:32 +000078 public void testLoadingActivity() throws IOException {
79 // During loading phase, state and activity, as reported by the PackageProgressReceiver,
80 // should be visible in the progress bar.
81 String state = "42 packages loaded";
82 String activity = "currently loading //src/foo/bar and 17 more";
83 PackageProgressReceiver progress = Mockito.mock(PackageProgressReceiver.class);
84 when(progress.progressState()).thenReturn(new Pair<String, String>(state, activity));
85
86 ManualClock clock = new ManualClock();
87 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
88
89 stateTracker.loadingStarted(new LoadingPhaseStartedEvent(progress));
90
91 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
92 stateTracker.writeProgressBar(terminalWriter);
93 String output = terminalWriter.getTranscript();
94
95 assertTrue(
96 "Output should indicate that we are in the loading phase, but was:\n" + output,
97 output.contains("Loading"));
98 assertTrue(
99 "Output should contain loading state '" + state + "', but was:\n" + output,
100 output.contains(state));
101 assertTrue(
102 "Output should contain loading state '" + activity + "', but was:\n" + output,
103 output.contains(activity));
104 }
105
106 @Test
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000107 public void testActionVisible() throws IOException {
108 // If there is only one action running, it should be visible
Klaus Aehligc0c88842016-04-11 12:07:38 +0000109 // somewhere in the progress bar, and also the short version thereof.
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000110
111 String message = "Building foo";
Klaus Aehliga63d9612016-04-04 12:15:23 +0000112 ManualClock clock = new ManualClock();
113 clock.advanceMillis(120000);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000114
Klaus Aehliga63d9612016-04-04 12:15:23 +0000115 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000116 stateTracker.actionStarted(new ActionStartedEvent(mockAction(message, "bar/foo"), 123456789));
Klaus Aehligc0c88842016-04-11 12:07:38 +0000117
Klaus Aehliged453e02016-04-15 11:29:05 +0000118 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000119 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000120 String output = terminalWriter.getTranscript();
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000121 assertTrue(
122 "Action message '" + message + "' should be present in output: " + output,
123 output.contains(message));
Klaus Aehligc0c88842016-04-11 12:07:38 +0000124
125 terminalWriter = new LoggingTerminalWriter();
126 stateTracker.writeProgressBar(terminalWriter, /* shortVersion=*/ true);
Klaus Aehliged453e02016-04-15 11:29:05 +0000127 output = terminalWriter.getTranscript();
Klaus Aehligc0c88842016-04-11 12:07:38 +0000128 assertTrue(
129 "Action message '" + message + "' should be present in short output: " + output,
130 output.contains(message));
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000131 }
132
133 @Test
134 public void testCompletedActionNotShown() throws IOException {
Klaus Aehligc0c88842016-04-11 12:07:38 +0000135 // Completed actions should not be reported in the progress bar, nor in the
136 // short progress bar.
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000137
138 String messageFast = "Running quick action";
139 String messageSlow = "Running slow action";
140
Klaus Aehliga63d9612016-04-04 12:15:23 +0000141 ManualClock clock = new ManualClock();
142 clock.advanceMillis(120000);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000143 Action fastAction = mockAction(messageFast, "foo/fast");
144 Action slowAction = mockAction(messageSlow, "bar/slow");
Klaus Aehliga63d9612016-04-04 12:15:23 +0000145 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000146 stateTracker.actionStarted(new ActionStartedEvent(fastAction, 123456789));
147 stateTracker.actionStarted(new ActionStartedEvent(slowAction, 123456999));
148 stateTracker.actionCompletion(new ActionCompletionEvent(20, fastAction));
149
Klaus Aehliged453e02016-04-15 11:29:05 +0000150 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000151 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000152 String output = terminalWriter.getTranscript();
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000153 assertFalse(
154 "Completed action '" + messageFast + "' should not be present in output: " + output,
155 output.contains(messageFast));
156 assertTrue(
157 "Only running action '" + messageSlow + "' should be present in output: " + output,
158 output.contains(messageSlow));
Klaus Aehligc0c88842016-04-11 12:07:38 +0000159
160 terminalWriter = new LoggingTerminalWriter();
161 stateTracker.writeProgressBar(terminalWriter, /* shortVersion=*/ true);
Klaus Aehliged453e02016-04-15 11:29:05 +0000162 output = terminalWriter.getTranscript();
Klaus Aehligc0c88842016-04-11 12:07:38 +0000163 assertFalse(
164 "Completed action '" + messageFast + "' should not be present in short output: " + output,
165 output.contains(messageFast));
166 assertTrue(
167 "Only running action '" + messageSlow + "' should be present in short output: " + output,
168 output.contains(messageSlow));
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000169 }
170
171 @Test
172 public void testOldestActionVisible() throws IOException {
Klaus Aehligc0c88842016-04-11 12:07:38 +0000173 // The earliest-started action is always visible somehow in the progress bar
174 // and its short version.
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000175
176 String messageOld = "Running the first-started action";
177
Klaus Aehliga63d9612016-04-04 12:15:23 +0000178 ManualClock clock = new ManualClock();
179 clock.advanceMillis(120000);
180 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000181 stateTracker.actionStarted(
182 new ActionStartedEvent(mockAction(messageOld, "bar/foo"), 123456789));
183 for (int i = 0; i < 30; i++) {
184 stateTracker.actionStarted(
185 new ActionStartedEvent(
186 mockAction("Other action " + i, "some/other/actions/number" + i), 123456790 + i));
187 }
188
Klaus Aehliged453e02016-04-15 11:29:05 +0000189 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000190 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000191 String output = terminalWriter.getTranscript();
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000192 assertTrue(
193 "Longest running action '" + messageOld + "' should be visible in output: " + output,
194 output.contains(messageOld));
Klaus Aehligc0c88842016-04-11 12:07:38 +0000195
Klaus Aehliged453e02016-04-15 11:29:05 +0000196 terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehligc0c88842016-04-11 12:07:38 +0000197 stateTracker.writeProgressBar(terminalWriter, /* shortVersion=*/ true);
Klaus Aehliged453e02016-04-15 11:29:05 +0000198 output = terminalWriter.getTranscript();
Klaus Aehligc0c88842016-04-11 12:07:38 +0000199 assertTrue(
200 "Longest running action '" + messageOld + "' should be visible in short output: " + output,
201 output.contains(messageOld));
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000202 }
Klaus Aehlige25642a2016-04-04 13:31:28 +0000203
204 @Test
Klaus Aehligcd211ee2016-06-21 08:44:15 +0000205 public void testSampleSize() throws IOException {
206 // Verify that the number of actions shown in the progress bar can be set as sample size.
207 ManualClock clock = new ManualClock();
208 clock.advanceMillis(TimeUnit.SECONDS.toMillis(123));
209 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
210 clock.advanceMillis(TimeUnit.SECONDS.toMillis(2));
211
212 // Start 10 actions (numbered 0 to 9).
213 for (int i = 0; i < 10; i++) {
214 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
215 Action action = mockAction("Performing action A" + i + ".", "action_A" + i + ".out");
216 stateTracker.actionStarted(new ActionStartedEvent(action, clock.nanoTime()));
217 }
218
219 // For various sample sizes verify the progress bar
220 for (int i = 1; i < 11; i++) {
221 stateTracker.setSampleSize(i);
222 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
223 stateTracker.writeProgressBar(terminalWriter);
224 String output = terminalWriter.getTranscript();
225 assertTrue(
226 "Action " + (i - 1) + " should still be shown in the output: '" + output,
227 output.contains("A" + (i - 1) + "."));
228 assertFalse(
229 "Action " + i + " should not be shown in the output: " + output,
230 output.contains("A" + i + "."));
231 if (i < 10) {
232 assertTrue("Ellipsis symbol should be shown in output: " + output, output.contains("..."));
233 } else {
234 assertFalse(
235 "Ellipsis symbol should not be shown in output: " + output, output.contains("..."));
236 }
237 }
238 }
239
240 @Test
Klaus Aehlige25642a2016-04-04 13:31:28 +0000241 public void testTimesShown() throws IOException {
242 // For sufficiently long running actions, the time that has passed since their start is shown.
Klaus Aehligc0c88842016-04-11 12:07:38 +0000243 // 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 +0000244
245 ManualClock clock = new ManualClock();
246 clock.advanceMillis(TimeUnit.SECONDS.toMillis(123));
247 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
248 clock.advanceMillis(TimeUnit.SECONDS.toMillis(2));
249
250 stateTracker.actionStarted(
251 new ActionStartedEvent(mockAction("First action", "foo"), clock.nanoTime()));
252 clock.advanceMillis(TimeUnit.SECONDS.toMillis(7));
253 stateTracker.actionStarted(
254 new ActionStartedEvent(mockAction("Second action", "bar"), clock.nanoTime()));
255 clock.advanceMillis(TimeUnit.SECONDS.toMillis(20));
256
Klaus Aehliged453e02016-04-15 11:29:05 +0000257 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehlige25642a2016-04-04 13:31:28 +0000258 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000259 String output = terminalWriter.getTranscript();
Klaus Aehlige25642a2016-04-04 13:31:28 +0000260 assertTrue(
261 "Runtime of first action should be visible in output: " + output, output.contains("27s"));
262 assertTrue(
263 "Runtime of second action should be visible in output: " + output, output.contains("20s"));
Klaus Aehligc0c88842016-04-11 12:07:38 +0000264
Klaus Aehliged453e02016-04-15 11:29:05 +0000265 terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehligc0c88842016-04-11 12:07:38 +0000266 stateTracker.writeProgressBar(terminalWriter, /* shortVersion=*/ true);
Klaus Aehliged453e02016-04-15 11:29:05 +0000267 output = terminalWriter.getTranscript();
Klaus Aehligc0c88842016-04-11 12:07:38 +0000268 assertTrue(
269 "Runtime of first action should be visible in short output: " + output,
270 output.contains("27s"));
Klaus Aehlige25642a2016-04-04 13:31:28 +0000271 }
272
Klaus Aehlig2ce24d42016-04-04 15:54:58 +0000273 @Test
274 public void initialProgressBarTimeIndependent() {
275 ManualClock clock = new ManualClock();
276 clock.advanceMillis(TimeUnit.SECONDS.toMillis(123));
277 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
278
279 assertFalse(
280 "Initial progress status should be time independent",
281 stateTracker.progressBarTimeDependent());
282 }
283
284 @Test
285 public void runningActionTimeIndependent() {
286 ManualClock clock = new ManualClock();
287 clock.advanceMillis(TimeUnit.SECONDS.toMillis(123));
288 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
289 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
290 stateTracker.actionStarted(
291 new ActionStartedEvent(mockAction("Some action", "foo"), clock.nanoTime()));
292
293 assertTrue(
294 "Progress bar showing a running action should be time dependent",
295 stateTracker.progressBarTimeDependent());
296 }
Klaus Aehligd232d232016-04-13 09:51:25 +0000297
298 @Test
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000299 public void testCountVisible() throws Exception {
Klaus Aehligd232d232016-04-13 09:51:25 +0000300 // The test count should be visible in the status bar, as well as the short status bar
301 ManualClock clock = new ManualClock();
302 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
303 TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000304 Label labelA = Label.parseAbsolute("//foo/bar:baz");
Klaus Aehligd232d232016-04-13 09:51:25 +0000305 ConfiguredTarget targetA = Mockito.mock(ConfiguredTarget.class);
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000306 when(targetA.getLabel()).thenReturn(labelA);
Klaus Aehligd232d232016-04-13 09:51:25 +0000307 ConfiguredTarget targetB = Mockito.mock(ConfiguredTarget.class);
308 when(filteringComplete.getTestTargets()).thenReturn(ImmutableSet.of(targetA, targetB));
309 TestSummary testSummary = Mockito.mock(TestSummary.class);
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000310 when(testSummary.getTarget()).thenReturn(targetA);
311
Klaus Aehligd232d232016-04-13 09:51:25 +0000312 stateTracker.testFilteringComplete(filteringComplete);
313 stateTracker.testSummary(testSummary);
314
Klaus Aehliged453e02016-04-15 11:29:05 +0000315 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehligd232d232016-04-13 09:51:25 +0000316 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000317 String output = terminalWriter.getTranscript();
Klaus Aehligd232d232016-04-13 09:51:25 +0000318 assertTrue(
319 "Test count should be visible in output: " + output, output.contains(" 1 / 2 tests"));
320
Klaus Aehliged453e02016-04-15 11:29:05 +0000321 terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
Klaus Aehligd232d232016-04-13 09:51:25 +0000322 stateTracker.writeProgressBar(terminalWriter, /* shortVersion=*/ true);
Klaus Aehliged453e02016-04-15 11:29:05 +0000323 output = terminalWriter.getTranscript();
Klaus Aehligd232d232016-04-13 09:51:25 +0000324 assertTrue(
325 "Test count should be visible in short output: " + output, output.contains(" 1 / 2 tests"));
326 }
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000327
328 @Test
329 public void testPassedVisible() throws Exception {
Klaus Aehlig07122cf2016-06-02 16:04:26 +0000330 // 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 +0000331 ManualClock clock = new ManualClock();
332 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
333 TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
334 Label labelA = Label.parseAbsolute("//foo/bar:baz");
335 ConfiguredTarget targetA = Mockito.mock(ConfiguredTarget.class);
336 when(targetA.getLabel()).thenReturn(labelA);
337 ConfiguredTarget targetB = Mockito.mock(ConfiguredTarget.class);
338 when(filteringComplete.getTestTargets()).thenReturn(ImmutableSet.of(targetA, targetB));
339 TestSummary testSummary = Mockito.mock(TestSummary.class);
340 when(testSummary.getStatus()).thenReturn(BlazeTestStatus.PASSED);
341 when(testSummary.getTarget()).thenReturn(targetA);
342
343 stateTracker.testFilteringComplete(filteringComplete);
344 stateTracker.testSummary(testSummary);
345
Klaus Aehlig07122cf2016-06-02 16:04:26 +0000346 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter();
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000347 stateTracker.writeProgressBar(terminalWriter);
Klaus Aehliged453e02016-04-15 11:29:05 +0000348 String output = terminalWriter.getTranscript();
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000349
Klaus Aehlig07122cf2016-06-02 16:04:26 +0000350 String expected = LoggingTerminalWriter.OK + labelA;
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000351 assertTrue(
Klaus Aehlig07122cf2016-06-02 16:04:26 +0000352 "Sequence '" + expected + "' should be present in colored progress bar: " + output,
353 output.contains(expected));
354 }
355
356 @Test
357 public void testFailedVisible() throws Exception {
358 // The last test should still be visible in the long status bar, and colored as fail if it
359 // did not pass.
360 ManualClock clock = new ManualClock();
361 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
362 TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
363 Label labelA = Label.parseAbsolute("//foo/bar:baz");
364 ConfiguredTarget targetA = Mockito.mock(ConfiguredTarget.class);
365 when(targetA.getLabel()).thenReturn(labelA);
366 ConfiguredTarget targetB = Mockito.mock(ConfiguredTarget.class);
367 when(filteringComplete.getTestTargets()).thenReturn(ImmutableSet.of(targetA, targetB));
368 TestSummary testSummary = Mockito.mock(TestSummary.class);
369 when(testSummary.getStatus()).thenReturn(BlazeTestStatus.FAILED);
370 when(testSummary.getTarget()).thenReturn(targetA);
371
372 stateTracker.testFilteringComplete(filteringComplete);
373 stateTracker.testSummary(testSummary);
374
375 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter();
376 stateTracker.writeProgressBar(terminalWriter);
377 String output = terminalWriter.getTranscript();
378
379 String expected = LoggingTerminalWriter.FAIL + labelA;
380 assertTrue(
381 "Sequence '" + expected + "' should be present in colored progress bar: " + output,
382 output.contains(expected));
Klaus Aehligb8d0c6b2016-04-13 11:06:41 +0000383 }
Klaus Aehlig6d0876a2016-04-15 14:41:07 +0000384
Klaus Aehliga4c7d252016-05-20 10:44:21 +0000385 @Test
386 public void testSensibleShortening() throws Exception {
387 // Verify that in the typical case, we shorten the progress message by shortening
388 // the path implicit in it, that can also be extracted from the label. In particular,
389 // the parts
390 ManualClock clock = new ManualClock();
391 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock, 70);
392 Action action = mockAction(
393 "Building some/very/very/long/path/for/some/library/directory/foo.jar (42 source files)",
394 "/home/user/bazel/out/abcdef/some/very/very/long/path/for/some/library/directory/foo.jar");
395 Label label =
396 Label.parseAbsolute("//some/very/very/long/path/for/some/library/directory:libfoo");
Dmitry Lomov15756522016-12-16 16:52:37 +0000397 ActionOwner owner = ActionOwner.create(
398 label, ImmutableList.<AspectDescriptor>of(), null, null, null, "fedcba", null);
Klaus Aehliga4c7d252016-05-20 10:44:21 +0000399 when(action.getOwner()).thenReturn(owner);
400
401 clock.advanceMillis(TimeUnit.SECONDS.toMillis(3));
402 stateTracker.actionStarted(new ActionStartedEvent(action, clock.nanoTime()));
403 clock.advanceMillis(TimeUnit.SECONDS.toMillis(5));
404
405 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
406 stateTracker.writeProgressBar(terminalWriter);
407 String output = terminalWriter.getTranscript();
408
409 assertTrue(
410 "Progress bar should contain 'Building ', but was:\n" + output,
411 output.contains("Building "));
412 assertTrue(
413 "Progress bar should contain 'foo.jar (42 source files)', but was:\n" + output,
414 output.contains("foo.jar (42 source files)"));
415 }
416
Klaus Aehlig0b26b422016-06-17 14:17:26 +0000417 @Test
418 public void testActionStrategyVisible() throws Exception {
419 // verify that, if a strategy was reported for a shown action, it is visible
420 // in the progress bar.
421 String strategy = "verySpecialStrategy";
422 String primaryOutput = "some/path/to/a/file";
423
424 ManualClock clock = new ManualClock();
425 Path path = outputBase.getRelative(new PathFragment(primaryOutput));
426 Artifact artifact = new Artifact(path, Root.asSourceRoot(path));
427 ActionExecutionMetadata actionMetadata = Mockito.mock(ActionExecutionMetadata.class);
Ulf Adams17e20332017-03-07 15:51:39 +0000428 when(actionMetadata.getOwner()).thenReturn(Mockito.mock(ActionOwner.class));
Klaus Aehlig0b26b422016-06-17 14:17:26 +0000429 when(actionMetadata.getPrimaryOutput()).thenReturn(artifact);
430
431 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
432 stateTracker.actionStarted(
433 new ActionStartedEvent(mockAction("Some random action", primaryOutput), clock.nanoTime()));
434 stateTracker.actionStatusMessage(ActionStatusMessage.runningStrategy(actionMetadata, strategy));
435
436 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
437 stateTracker.writeProgressBar(terminalWriter);
438 String output = terminalWriter.getTranscript();
439
440 assertTrue(
441 "Output should mention strategy '" + strategy + "', but was: " + output,
442 output.contains(strategy));
443 }
444
Klaus Aehlig6d0876a2016-04-15 14:41:07 +0000445 private void doTestOutputLength(boolean withTest, int actions) throws Exception {
446 // If we target 70 characters, then there should be enough space to both,
447 // keep the line limit, and show the local part of the running actions and
448 // the passed test.
449 ManualClock clock = new ManualClock();
450 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock, 70);
451
452 Action foobuildAction = mockAction(
453 "Building //src/some/very/long/path/long/long/long/long/long/long/long/foo/foobuild.jar",
454 "//src/some/very/long/path/long/long/long/long/long/long/long/foo:foobuild");
455 Action bazbuildAction = mockAction(
456 "Building //src/some/very/long/path/long/long/long/long/long/long/long/baz/bazbuild.jar",
457 "//src/some/very/long/path/long/long/long/long/long/long/long/baz:bazbuild");
458
Klaus Aehlig0b26b422016-06-17 14:17:26 +0000459 Label bartestLabel =
460 Label.parseAbsolute(
461 "//src/another/very/long/long/path/long/long/long/long/long/long/long/long/bars:bartest");
Klaus Aehlig6d0876a2016-04-15 14:41:07 +0000462 ConfiguredTarget bartestTarget = Mockito.mock(ConfiguredTarget.class);
463 when(bartestTarget.getLabel()).thenReturn(bartestLabel);
464
465 TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
466 when(filteringComplete.getTestTargets()).thenReturn(ImmutableSet.of(bartestTarget));
467
468 TestSummary testSummary = Mockito.mock(TestSummary.class);
469 when(testSummary.getStatus()).thenReturn(BlazeTestStatus.PASSED);
470 when(testSummary.getTarget()).thenReturn(bartestTarget);
471
472 if (actions >= 1) {
473 stateTracker.actionStarted(new ActionStartedEvent(foobuildAction, 123456789));
474 }
475 if (actions >= 2) {
476 stateTracker.actionStarted(new ActionStartedEvent(bazbuildAction, 123456900));
477 }
478 if (withTest) {
479 stateTracker.testFilteringComplete(filteringComplete);
480 stateTracker.testSummary(testSummary);
481 }
482
483 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
484 stateTracker.writeProgressBar(terminalWriter);
485 String output = terminalWriter.getTranscript();
486
487 assertTrue(
488 "Only lines with at most 70 chars should be present in the output:\n" + output,
489 longestLine(output) <= 70);
490 if (actions >= 1) {
491 assertTrue(
492 "Running action 'foobuild' should be mentioned in output:\n" + output,
493 output.contains("foobuild"));
494 }
495 if (actions >= 2) {
496 assertTrue(
497 "Running action 'bazbuild' should be mentioned in output:\n" + output,
498 output.contains("bazbuild"));
499 }
500 if (withTest) {
501 assertTrue(
502 "Passed test ':bartest' should be mentioned in output:\n" + output,
503 output.contains(":bartest"));
504 }
505 }
506
507 @Test
508 public void testOutputLength() throws Exception {
509 for (int i = 0; i < 3; i++) {
510 doTestOutputLength(true, i);
511 doTestOutputLength(false, i);
512 }
513 }
Klaus Aehligc6d3ccc2016-05-24 12:58:09 +0000514
515 @Test
516 public void testAggregation() throws Exception {
517 // Assert that actions for the same test are aggregated so that an action afterwards
518 // is still shown.
519 ManualClock clock = new ManualClock();
520 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1234));
521 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock, 80);
522
523 Label labelFooTest = Label.parseAbsolute("//foo/bar:footest");
524 ConfiguredTarget targetFooTest = Mockito.mock(ConfiguredTarget.class);
525 when(targetFooTest.getLabel()).thenReturn(labelFooTest);
Carmi Grushko33aa3062016-11-11 02:45:29 +0000526 ActionOwner fooOwner =
Dmitry Lomov15756522016-12-16 16:52:37 +0000527 ActionOwner.create(labelFooTest,
528 ImmutableList.<AspectDescriptor>of(), null, null, null, "abcdef", null);
Klaus Aehligc6d3ccc2016-05-24 12:58:09 +0000529
530 Label labelBarTest = Label.parseAbsolute("//baz:bartest");
531 ConfiguredTarget targetBarTest = Mockito.mock(ConfiguredTarget.class);
532 when(targetBarTest.getLabel()).thenReturn(labelBarTest);
533 TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
534 when(filteringComplete.getTestTargets())
535 .thenReturn(ImmutableSet.of(targetFooTest, targetBarTest));
Carmi Grushko33aa3062016-11-11 02:45:29 +0000536 ActionOwner barOwner =
Dmitry Lomov15756522016-12-16 16:52:37 +0000537 ActionOwner.create(labelBarTest,
538 ImmutableList.<AspectDescriptor>of(), null, null, null, "fedcba", null);
Klaus Aehligc6d3ccc2016-05-24 12:58:09 +0000539
540 stateTracker.testFilteringComplete(filteringComplete);
541
542 // First produce 10 actions for footest...
543 for (int i = 0; i < 10; i++) {
544 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
545 Action action = mockAction("Testing foo, shard " + i, "testlog_foo_" + i);
546 when(action.getOwner()).thenReturn(fooOwner);
547 stateTracker.actionStarted(new ActionStartedEvent(action, clock.nanoTime()));
548 }
549 // ...then produce 10 actions for bartest...
550 for (int i = 0; i < 10; i++) {
551 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
552 Action action = mockAction("Testing bar, shard " + i, "testlog_bar_" + i);
553 when(action.getOwner()).thenReturn(barOwner);
554 stateTracker.actionStarted(new ActionStartedEvent(action, clock.nanoTime()));
555 }
556 // ...and finally a completely unrelated action
557 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
558 stateTracker.actionStarted(
559 new ActionStartedEvent(mockAction("Other action", "other/action"), clock.nanoTime()));
560 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
561
562 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
563 stateTracker.writeProgressBar(terminalWriter);
564 String output = terminalWriter.getTranscript();
565
566 assertTrue(
567 "Progress bar should contain ':footest', but was:\n" + output, output.contains(":footest"));
568 assertTrue(
569 "Progress bar should contain ':bartest', but was:\n" + output, output.contains(":bartest"));
570 assertTrue(
571 "Progress bar should contain 'Other action', but was:\n" + output,
572 output.contains("Other action"));
573 }
Klaus Aehlige52813b2016-08-02 10:06:07 +0000574
575
576 @Test
577 public void testSuffix() throws Exception {
578 assertEquals("bar", ExperimentalStateTracker.suffix("foobar", 3));
579 assertEquals("", ExperimentalStateTracker.suffix("foo", -2));
580 assertEquals("foobar", ExperimentalStateTracker.suffix("foobar", 200));
581 }
Klaus Aehlig5c06b432017-03-01 18:00:39 +0000582
583 @Test
584 public void testDownloadShown() throws Exception {
585 // Verify that, whenever a single download is running in loading face, it is shown in the status
586 // bar.
587 ManualClock clock = new ManualClock();
588 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1234));
589 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock, 80);
590
591 URL url = new URL("http://example.org/first/dep");
592
593 stateTracker.buildStarted(null);
594 stateTracker.downloadProgress(new DownloadProgressEvent(url));
595 clock.advanceMillis(TimeUnit.SECONDS.toMillis(6));
596
597 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
598 stateTracker.writeProgressBar(terminalWriter);
599 String output = terminalWriter.getTranscript();
600
601 assertTrue(
602 "Progress bar should contain '" + url.toString() + "', but was:\n" + output,
603 output.contains(url.toString()));
604 assertTrue("Progress bar should contain '6s', but was:\n" + output, output.contains("6s"));
605
606 // Progress on the pending download should be reported appropriately
607 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
608 stateTracker.downloadProgress(new DownloadProgressEvent(url, 256));
609
610 terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
611 stateTracker.writeProgressBar(terminalWriter);
612 output = terminalWriter.getTranscript();
613
614 assertTrue(
615 "Progress bar should contain '" + url.toString() + "', but was:\n" + output,
616 output.contains(url.toString()));
617 assertTrue("Progress bar should contain '7s', but was:\n" + output, output.contains("7s"));
618 assertTrue("Progress bar should contain '256', but was:\n" + output, output.contains("256"));
619
620 // After finishing the download, it should no longer be reported.
621 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
622 stateTracker.downloadProgress(new DownloadProgressEvent(url, 256, true));
623
624 terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
625 stateTracker.writeProgressBar(terminalWriter);
626 output = terminalWriter.getTranscript();
627
628 assertFalse(
629 "Progress bar should not contain url, but was:\n" + output, output.contains("example.org"));
630 }
631
632 @Test
633 public void testDownloadOutputLength() throws Exception {
634 // Verify that URLs are shortened in a reasonable way, if the terminal is not wide enough
635 // Also verify that the length is respected, even if only a download sample is shown.
636 ManualClock clock = new ManualClock();
637 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1234));
638 ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock, 60);
639 URL url = new URL("http://example.org/some/really/very/very/long/path/filename.tar.gz");
640
641 stateTracker.buildStarted(null);
642 stateTracker.downloadProgress(new DownloadProgressEvent(url));
643 clock.advanceMillis(TimeUnit.SECONDS.toMillis(6));
644 for (int i = 0; i < 10; i++) {
645 stateTracker.downloadProgress(
646 new DownloadProgressEvent(
647 new URL(
648 "http://otherhost.example/another/also/length/path/to/another/download"
649 + i
650 + ".zip")));
651 clock.advanceMillis(TimeUnit.SECONDS.toMillis(1));
652 }
653
654 LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
655 stateTracker.writeProgressBar(terminalWriter);
656 String output = terminalWriter.getTranscript();
657
658 assertTrue(
659 "Only lines with at most 60 chars should be present in the output:\n" + output,
660 longestLine(output) <= 60);
661 assertTrue(
662 "Output still should contain the filename, but was:\n" + output,
663 output.contains("filename.tar.gz"));
664 assertTrue(
665 "Output still should contain the host name, but was:\n" + output,
666 output.contains("example.org"));
667 }
668
Klaus Aehlig8cad4bd2016-03-14 11:13:58 +0000669}