Skip to content

Commit dc7a7d6

Browse files
authored
[Core] Flush pretty output manually (#2573)
For the sake of efficiency and performance we write to buffered writers. However, the pretty plugin is expected to print scenarios as they're started and steps as they're finished. This was initially resolved by flushing the `NiceAppendable` on every write. This turned out to have performance impact (#2481) and interact poorly with tools that expected (#2536) us to be better behaved. By having `NiceAppendable` flush only when the underlying buffer was full these problems were resolved (#2541) . However, because the underlying buffer is 8KiB the pretty formatters output would effectively sit in a buffer until the writer was closed. So now we flush the pretty and progress output manually after each event. This strikes a balance somewhere between the flush-everything-all-the-time and flush-when-full approaches. Fixes: #2563
1 parent 0ee15f0 commit dc7a7d6

File tree

13 files changed

+107
-231
lines changed

13 files changed

+107
-231
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111
* [Core] Warn when glue path is passed as file scheme instead of classpath ([#2547](https://github.com/cucumber/cucumber-jvm/pull/2547) M.P. Korstanje)
1212

1313
### Changed
14+
* [Core] Flush pretty output manually ([#2573](https://github.com/cucumber/cucumber-jvm/pull/2573) M.P. Korstanje)
1415

1516
### Deprecated
1617

1718
### Removed
1819

1920
### Fixed
20-
* [Spring] Cleanly stop after failure to start application context
21+
* [Spring] Cleanly stop after failure to start application context ([#2570](https://github.com/cucumber/cucumber-jvm/pull/2570) M.P. Korstanje)
22+
* [JUnit] Scenario logging does not show up in step notifications ([#2563](https://github.com/cucumber/cucumber-jvm/pull/2545) M.P. Korstanje)
2123

2224
## [7.3.4] (2022-05-02)
2325

core/src/main/java/io/cucumber/core/plugin/AnsiEscapes.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ static AnsiEscapes up(int count) {
3030
return new AnsiEscapes(count + "A");
3131
}
3232

33-
void appendTo(NiceAppendable a) {
34-
a.append(ESC).append(BRACKET).append(value);
35-
}
36-
3733
@Override
3834
public String toString() {
3935
StringBuilder sb = new StringBuilder();

core/src/main/java/io/cucumber/core/plugin/MessageFormatter.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ private void writeMessage(Envelope envelope) {
2525
try {
2626
Jackson.OBJECT_MAPPER.writeValue(writer, envelope);
2727
writer.write("\n");
28-
writer.flush();
2928
if (envelope.getTestRunFinished().isPresent()) {
3029
writer.close();
3130
}

core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java

Lines changed: 0 additions & 96 deletions
This file was deleted.

core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.io.File;
2323
import java.io.IOException;
2424
import java.io.OutputStream;
25+
import java.io.PrintWriter;
2526
import java.io.StringReader;
2627
import java.net.URI;
2728
import java.net.URISyntaxException;
@@ -37,6 +38,12 @@
3738
import static java.lang.Math.max;
3839
import static java.util.Locale.ROOT;
3940

41+
/**
42+
* Prints a pretty report of the scenario execution as it happens.
43+
* <p>
44+
* When scenarios are executed concurrently the output will interleave. This is
45+
* to be expected.
46+
*/
4047
public final class PrettyFormatter implements ConcurrentEventListener, ColorAware {
4148

4249
private static final String SCENARIO_INDENT = "";
@@ -45,11 +52,11 @@ public final class PrettyFormatter implements ConcurrentEventListener, ColorAwar
4552

4653
private final Map<UUID, Integer> commentStartIndex = new HashMap<>();
4754

48-
private final NiceAppendable out;
55+
private final PrintWriter out;
4956
private Formats formats = ansi();
5057

5158
public PrettyFormatter(OutputStream out) {
52-
this.out = new NiceAppendable(new UTF8OutputStreamWriter(out));
59+
this.out = new UTF8PrintWriter(out);
5360
}
5461

5562
@Override
@@ -66,25 +73,27 @@ private void handleTestCaseStarted(TestCaseStarted event) {
6673
preCalculateLocationIndent(event);
6774
printTags(event);
6875
printScenarioDefinition(event);
76+
out.flush();
6977
}
7078

7179
private void handleTestStepFinished(TestStepFinished event) {
7280
printStep(event);
7381
printError(event);
82+
out.flush();
7483
}
7584

7685
private void handleWrite(WriteEvent event) {
7786
out.println();
7887
printText(event);
7988
out.println();
80-
89+
out.flush();
8190
}
8291

8392
private void handleEmbed(EmbedEvent event) {
8493
out.println();
8594
printEmbedding(event);
8695
out.println();
87-
96+
out.flush();
8897
}
8998

9099
private void handleTestRunFinished(TestRunFinished event) {
@@ -188,9 +197,8 @@ private void printText(WriteEvent event) {
188197
while ((line = lines.readLine()) != null) {
189198
builder.append(STEP_SCENARIO_INDENT)
190199
.append(line)
191-
.append(System.lineSeparator()); // Add system line
192-
// separator - \n won't
193-
// do it!
200+
// Add system line separator - \n won't do it!
201+
.append(System.lineSeparator());
194202
}
195203
} catch (IOException e) {
196204
throw new CucumberException(e);

core/src/main/java/io/cucumber/core/plugin/ProgressFormatter.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.cucumber.plugin.event.TestStepFinished;
1010

1111
import java.io.OutputStream;
12+
import java.io.PrintWriter;
1213
import java.util.HashMap;
1314
import java.util.Map;
1415

@@ -35,13 +36,11 @@ public final class ProgressFormatter implements ConcurrentEventListener, ColorAw
3536
}
3637
};
3738

38-
private final NiceAppendable out;
39+
private final PrintWriter out;
3940
private boolean monochrome = false;
4041

4142
public ProgressFormatter(OutputStream out) {
42-
// Configure the NiceAppendable to flush on every append, since the
43-
// point of this formatter is to display a progress bar.
44-
this.out = new NiceAppendable(new UTF8OutputStreamWriter(out), true);
43+
this.out = new UTF8PrintWriter(out);
4544
}
4645

4746
@Override
@@ -71,6 +70,7 @@ private void handleTestStepFinished(TestStepFinished event) {
7170
AnsiEscapes.RESET.appendTo(buffer);
7271
}
7372
out.append(buffer);
73+
out.flush();
7474
}
7575

7676
private void handleTestRunFinished(TestRunFinished testRunFinished) {

core/src/main/java/io/cucumber/core/plugin/RerunFormatter.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import io.cucumber.plugin.event.TestRunFinished;
99

1010
import java.io.OutputStream;
11+
import java.io.PrintWriter;
1112
import java.net.URI;
1213
import java.util.ArrayList;
1314
import java.util.Collection;
@@ -23,11 +24,11 @@
2324
*/
2425
public final class RerunFormatter implements ConcurrentEventListener {
2526

26-
private final NiceAppendable out;
27+
private final PrintWriter out;
2728
private final Map<URI, Collection<Integer>> featureAndFailedLinesMapping = new HashMap<>();
2829

2930
public RerunFormatter(OutputStream out) {
30-
this.out = new NiceAppendable(new UTF8OutputStreamWriter(out));
31+
this.out = new UTF8PrintWriter(out);
3132
}
3233

3334
@Override
@@ -45,7 +46,7 @@ private void handleTestCaseFinished(TestCaseFinished event) {
4546
private void finishReport() {
4647
for (Map.Entry<URI, Collection<Integer>> entry : featureAndFailedLinesMapping.entrySet()) {
4748
FeatureWithLines featureWithLines = create(relativize(entry.getKey()), entry.getValue());
48-
out.println(featureWithLines.toString());
49+
out.println(featureWithLines);
4950
}
5051

5152
out.close();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.cucumber.core.plugin;
2+
3+
import java.io.OutputStream;
4+
import java.io.PrintWriter;
5+
import java.nio.charset.StandardCharsets;
6+
7+
final class UTF8PrintWriter extends PrintWriter {
8+
9+
UTF8PrintWriter(OutputStream out) {
10+
super(out, false, StandardCharsets.UTF_8);
11+
}
12+
13+
}

core/src/main/java/io/cucumber/core/plugin/UnusedStepsSummaryPrinter.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.cucumber.plugin.event.TestStepFinished;
1010

1111
import java.io.OutputStream;
12+
import java.io.PrintWriter;
1213
import java.util.Map;
1314
import java.util.Map.Entry;
1415
import java.util.Set;
@@ -23,11 +24,11 @@ public final class UnusedStepsSummaryPrinter implements ColorAware, ConcurrentEv
2324

2425
private final Map<String, String> registeredSteps = new TreeMap<>();
2526
private final Set<String> usedSteps = new TreeSet<>();
26-
private final NiceAppendable out;
27+
private final PrintWriter out;
2728
private Formats formats = ansi();
2829

2930
public UnusedStepsSummaryPrinter(OutputStream out) {
30-
this.out = new NiceAppendable(new UTF8OutputStreamWriter(out));
31+
this.out = new UTF8PrintWriter(out);
3132
}
3233

3334
@Override

core/src/test/java/io/cucumber/core/plugin/NiceAppendableTest.java

Lines changed: 0 additions & 53 deletions
This file was deleted.

0 commit comments

Comments
 (0)