Skip to content

Commit

Permalink
[Core] Flush pretty output manually (#2573)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mpkorstanje authored Jun 21, 2022
1 parent 0ee15f0 commit dc7a7d6
Show file tree
Hide file tree
Showing 13 changed files with 107 additions and 231 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
* [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)

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

### Deprecated

### Removed

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

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

Expand Down
4 changes: 0 additions & 4 deletions core/src/main/java/io/cucumber/core/plugin/AnsiEscapes.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ static AnsiEscapes up(int count) {
return new AnsiEscapes(count + "A");
}

void appendTo(NiceAppendable a) {
a.append(ESC).append(BRACKET).append(value);
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ private void writeMessage(Envelope envelope) {
try {
Jackson.OBJECT_MAPPER.writeValue(writer, envelope);
writer.write("\n");
writer.flush();
if (envelope.getTestRunFinished().isPresent()) {
writer.close();
}
Expand Down
96 changes: 0 additions & 96 deletions core/src/main/java/io/cucumber/core/plugin/NiceAppendable.java

This file was deleted.

22 changes: 15 additions & 7 deletions core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.net.URI;
import java.net.URISyntaxException;
Expand All @@ -37,6 +38,12 @@
import static java.lang.Math.max;
import static java.util.Locale.ROOT;

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

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

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

private final NiceAppendable out;
private final PrintWriter out;
private Formats formats = ansi();

public PrettyFormatter(OutputStream out) {
this.out = new NiceAppendable(new UTF8OutputStreamWriter(out));
this.out = new UTF8PrintWriter(out);
}

@Override
Expand All @@ -66,25 +73,27 @@ private void handleTestCaseStarted(TestCaseStarted event) {
preCalculateLocationIndent(event);
printTags(event);
printScenarioDefinition(event);
out.flush();
}

private void handleTestStepFinished(TestStepFinished event) {
printStep(event);
printError(event);
out.flush();
}

private void handleWrite(WriteEvent event) {
out.println();
printText(event);
out.println();

out.flush();
}

private void handleEmbed(EmbedEvent event) {
out.println();
printEmbedding(event);
out.println();

out.flush();
}

private void handleTestRunFinished(TestRunFinished event) {
Expand Down Expand Up @@ -188,9 +197,8 @@ private void printText(WriteEvent event) {
while ((line = lines.readLine()) != null) {
builder.append(STEP_SCENARIO_INDENT)
.append(line)
.append(System.lineSeparator()); // Add system line
// separator - \n won't
// do it!
// Add system line separator - \n won't do it!
.append(System.lineSeparator());
}
} catch (IOException e) {
throw new CucumberException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.cucumber.plugin.event.TestStepFinished;

import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

Expand All @@ -35,13 +36,11 @@ public final class ProgressFormatter implements ConcurrentEventListener, ColorAw
}
};

private final NiceAppendable out;
private final PrintWriter out;
private boolean monochrome = false;

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

@Override
Expand Down Expand Up @@ -71,6 +70,7 @@ private void handleTestStepFinished(TestStepFinished event) {
AnsiEscapes.RESET.appendTo(buffer);
}
out.append(buffer);
out.flush();
}

private void handleTestRunFinished(TestRunFinished testRunFinished) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import io.cucumber.plugin.event.TestRunFinished;

import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -23,11 +24,11 @@
*/
public final class RerunFormatter implements ConcurrentEventListener {

private final NiceAppendable out;
private final PrintWriter out;
private final Map<URI, Collection<Integer>> featureAndFailedLinesMapping = new HashMap<>();

public RerunFormatter(OutputStream out) {
this.out = new NiceAppendable(new UTF8OutputStreamWriter(out));
this.out = new UTF8PrintWriter(out);
}

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

out.close();
Expand Down
13 changes: 13 additions & 0 deletions core/src/main/java/io/cucumber/core/plugin/UTF8PrintWriter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.cucumber.core.plugin;

import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;

final class UTF8PrintWriter extends PrintWriter {

UTF8PrintWriter(OutputStream out) {
super(out, false, StandardCharsets.UTF_8);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.cucumber.plugin.event.TestStepFinished;

import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
Expand All @@ -23,11 +24,11 @@ public final class UnusedStepsSummaryPrinter implements ColorAware, ConcurrentEv

private final Map<String, String> registeredSteps = new TreeMap<>();
private final Set<String> usedSteps = new TreeSet<>();
private final NiceAppendable out;
private final PrintWriter out;
private Formats formats = ansi();

public UnusedStepsSummaryPrinter(OutputStream out) {
this.out = new NiceAppendable(new UTF8OutputStreamWriter(out));
this.out = new UTF8PrintWriter(out);
}

@Override
Expand Down
53 changes: 0 additions & 53 deletions core/src/test/java/io/cucumber/core/plugin/NiceAppendableTest.java

This file was deleted.

Loading

0 comments on commit dc7a7d6

Please sign in to comment.