Output consumers

Consume lines from std[out|err]

0.0.1

Use lines(Consumer<String>) to receive each line of the output as it is produced. The consumer is called from an internal I/O thread.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.assertj.core.api.Assertions;
import org.cliassured.CliAssured;

// List.add() will be called in a different thread, so use a thread safe List
List<String> collected = Collections.synchronizedList(new ArrayList<>());

CliAssured
    .command("echo", "Hello\nWorld")
    .then()
        .stdout()
            // Collect each line into a list
            .lines(collected::add)
    .execute()
    .assertSuccess();

Assertions.assertThat(collected).containsExactly("Hello", "World");

You can get all lines of the output as a Stream<String>. However that way is not recommended for commands producing a lot of output because of memory consumption. Using .then().std[out|err].lines(Consumer<String>) is much more memory efficient.

log()

0.0.1

Use log() to log each line at INFO level using an SLF4J logger named org.cliassured.stdout or org.cliassured.stderr respectively.

import org.cliassured.CliAssured;

CliAssured
    .command("echo", "Hello World!")
    .then()
        .stdout()
            // Log each line at INFO level via org.cliassured.stdout logger
            .log()
    .execute()
    .assertSuccess();

log(Consumer<String>)

0.0.1

To log to a custom consumer (e.g. a specific logger level), use log(Consumer<String>):

import org.cliassured.CliAssured;

Logger log = LoggerFactory.getLogger("my.custom.logger");

CliAssured
    .command("sh", "-c",
             "echo 'Hello from stdout'; echo 'Hello from stderr' 1>&2")
    .then()
        .stdout()
            // Log stdout lines on INFO level
            .log(log::info)
        .stderr()
            // Log stderr lines on ERROR level
            .log(log::error)
    .execute()
    .assertSuccess();

Awaiting a specific line

0.0.1

Use await(Consumer<String>) together with Await factory methods to block until a specific condition is met in the output. This is especially useful for testing long-running processes like servers, where you need to wait for a startup message before interacting with the process.

import java.time.Duration;
import org.assertj.core.api.Assertions;
import org.cliassured.Await;
import org.cliassured.Await.LineAwait;
import org.cliassured.CliAssured;
import org.cliassured.CommandProcess;

// Create an await condition that extracts a port number from a log line
LineAwait<Integer> awaitPort = Await
    // Wait for a line matching this regex
    .lineMatching("listening on port: (\\d+)")
    // Map the first capturing group to an int
    .map(Integer::parseInt);

try (CommandProcess proc = CliAssured
        .command("echo", "listening on port: 8080")
        .then()
            .stdout()
                // Register the await condition
                .await(awaitPort)
        // Start the process without blocking
        .start()) {

    // Block until the condition is satisfied or the timeout is reached
    int port = awaitPort.await(Duration.ofSeconds(10));
    Assertions.assertThat(port).isEqualTo(8080);
}

The Await class provides several factory methods:

  • Await.line(String) — wait for an exact line

  • Await.lineContaining(String) — wait for a line containing a substring

  • Await.lineContainingCaseInsensitive(String) — case-insensitive substring match

  • Await.lineMatching(String) — wait for a line matching a regex (supports capturing groups)

  • Await.lineMatching(Pattern) — compiled Pattern variant

  • Await.lineCount(int) — wait until N lines have been output

  • Await.lineSatifying(String, Predicate<String>) — wait for a line satisfying a custom predicate

All factory methods return a LineAwait<String> which can be transformed with .map(Function).