Dashboard¶
Your end-to-end tests pass. But do you see what they do?
Stove Dashboard is a local observability dashboard for your e2e test runs.
- Captures everything — HTTP calls, Kafka messages, database queries, gRPC calls, distributed traces, system snapshots
- Real-time web UI — updates live via SSE as your tests execute
- Single binary — receives events via gRPC, persists in SQLite, serves an embedded SPA
- Persistent — browse test runs after they complete, across sessions
Unlike Reporting (console output on failure) and Tracing (span collection for assertions), Dashboard gives you a persistent, browsable view of your test runs — including successful ones.
Install the CLI¶
Options:
Download the binary for your platform from GitHub Releases:
| Platform | Archive |
|---|---|
| macOS arm64 | stove-<version>-darwin-arm64.tar.gz |
| macOS amd64 | stove-<version>-darwin-amd64.tar.gz |
| Linux amd64 | stove-<version>-linux-amd64.tar.gz |
Each archive includes a .sha256 checksum file.
The CLI is a single binary with no runtime dependencies. It embeds the web UI, so there's nothing else to install.
Keep Versions Aligned
Keep stove-cli, the Stove BOM, and your Stove test dependencies on the same Stove version. The dashboard shows a warning when the runtime libraries and CLI drift apart, but matching versions avoids inconsistent dashboard data.
Quick Start¶
1. Start the dashboard
You'll see:
Stove CLI v0.23.0
HTTP server: http://localhost:4040
gRPC server: http://localhost:4041
Database: ~/.stove-dashboard.db
2. Add the dependency
3. Apply the tracing Gradle plugin
The tracing Gradle plugin attaches the OpenTelemetry agent to your test tasks, which is required for the dashboard's trace view to receive spans.
// build.gradle.kts
plugins {
id("com.trendyol.stove.tracing") version "<stove-version>"
}
stoveTracing {
serviceName.set("product-api")
}
See Tracing for the full plugin configuration reference.
4. Register in your Stove config
class StoveConfig : AbstractProjectConfig() {
override val extensions = listOf(StoveKotestExtension())
override suspend fun beforeProject() =
Stove().with {
dashboard { DashboardSystemOptions(appName = "product-api") }
tracing { enableSpanReceiver() } // recommended: enables distributed trace capture
// ... other systems
}.run()
override suspend fun afterProject() = Stove.stop()
}
@ExtendWith(StoveJUnitExtension::class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
abstract class BaseE2ETest {
companion object {
@JvmStatic @BeforeAll
fun setup() = runBlocking {
Stove().with {
dashboard { DashboardSystemOptions(appName = "product-api") }
tracing { enableSpanReceiver() }
// ... other systems
}.run()
}
@JvmStatic @AfterAll
fun teardown() = runBlocking { Stove.stop() }
}
}
5. Run your tests and open the dashboard
Navigate to http://localhost:4040. The UI updates in real time as tests execute.
If the dashboard shows a version mismatch warning, align your Stove BOM and test dependencies with the stove-cli version, or upgrade stove-cli to the runtime version reported by the selected app.
What Gets Captured¶
Once dashboard {} is registered, Stove automatically captures everything — no code changes to your tests:
| Event | Data |
|---|---|
| Run lifecycle | Start/end timestamps, app name, active systems, pass/fail counts |
| Test lifecycle | Test name, spec name, duration, status, error messages |
| Entries | Every http {}, kafka {}, postgresql {} assertion — system, action, input/output, expected/actual, trace ID |
| Spans | Distributed traces via OpenTelemetry — operation, service, duration, attributes, exceptions |
| Snapshots | System state at test boundaries — database contents, Kafka offsets, WireMock stubs |
The Dashboard¶
The embedded SPA provides four views for each test:
Timeline¶
Chronological list of every action the test performed. Each entry shows timestamp, system badge (color-coded), action name, and pass/fail indicator. Click any entry to expand full detail: input, output, expected vs. actual, error, metadata.
Recognized systems: HTTP, Kafka, PostgreSQL, MongoDB, Couchbase, Redis, Elasticsearch, WireMock, gRPC, MySQL, MSSQL, Cassandra.
Trace¶
Distributed trace tree built from OpenTelemetry spans. Spans are linked to tests via two mechanisms:
- Entry-based: spans sharing a
trace_idwith a test entry - Attribute-based: spans containing
x-stove-test-idin their attributes
The tree shows operation name, service, duration, status, relevant attributes (http.*, db.*, messaging.*, rpc.*), and exception details with stack traces.
Combine with Tracing
Dashboard's trace view is the visual counterpart to the Tracing component's console output. Enable both for the best experience: Tracing gives you assertion DSL and failure reports in the terminal, Dashboard gives you a browsable trace tree in the browser.
Snapshots¶
Grid of system state cards captured at test boundaries. Each card shows the system name with a color-coded icon and a summary of the captured state.
Kafka Explorer¶
Dedicated view filtering Kafka-specific entries. Shows consumed/published/failed message counts with expandable JSON payloads.
Configuration¶
DashboardSystemOptions¶
DashboardSystemOptions(
appName = "product-api", // required: identifies the application under test
cliHost = "localhost", // where the stove CLI is running
cliPort = 4041 // gRPC port of the stove CLI
)
| Parameter | Type | Default | Description |
|---|---|---|---|
appName |
String |
(required) | Application name for grouping test runs |
cliHost |
String |
"localhost" |
Hostname where stove CLI is running |
cliPort |
Int |
4041 |
gRPC port where stove CLI is listening |
CLI Options¶
stove [OPTIONS]
Options:
--port <PORT> HTTP port for the web UI and REST API [default: 4040]
--grpc-port <PORT> gRPC port for receiving events [default: 4041]
--db <PATH> Path to SQLite database file [default: ~/.stove-dashboard.db]
--clear Clear all stored data and exit
--fresh-start Back up and recreate the database, then start normally
-h, --help Print help
-V, --version Print version
# Run on custom ports
stove --port 8080 --grpc-port 8081
# Use a project-specific database
stove --db ./my-project-dashboard.db
# Reset all data (exits after clearing)
stove --clear
# Drop and recreate the database (backs up first, then starts servers)
stove --fresh-start
Fault Tolerance¶
The dashboard emitter is designed to never break your tests:
- Non-blocking event queue (capacity: 512)
- Auto-disables after 5 consecutive gRPC failures
- 3-second drain timeout on shutdown
- If the dashboard CLI is not running, tests continue normally with zero overhead
This means you can add dashboard {} to your config permanently. When the CLI is running, you get the dashboard. When it's not, nothing changes.
REST API¶
The dashboard exposes a REST API at /api/v1 for programmatic access:
| Method | Path | Description |
|---|---|---|
| GET | /apps |
List applications with latest run info |
| GET | /runs?app={name} |
List runs, optionally filtered by app |
| GET | /runs/{run_id} |
Get a specific run |
| GET | /runs/{run_id}/tests |
List tests in a run |
| GET | /runs/{run_id}/tests/{test_id}/entries |
List entries for a test |
| GET | /runs/{run_id}/tests/{test_id}/spans |
List spans linked to a test |
| GET | /runs/{run_id}/tests/{test_id}/snapshots |
List snapshots for a test |
| GET | /traces/{trace_id} |
Get all spans in a trace |
| GET | /events/stream |
SSE stream for real-time events |
SSE Events¶
The /events/stream endpoint delivers server-sent events with JSON payloads:
Event types: run_started, run_ended, test_started, test_ended, entry_recorded, span_recorded, snapshot.
Complete Example¶
class StoveConfig : AbstractProjectConfig() {
override val extensions = listOf(StoveKotestExtension())
override suspend fun beforeProject() =
Stove()
.with {
dashboard { DashboardSystemOptions(appName = "spring-example") }
tracing { enableSpanReceiver() }
httpClient {
HttpClientSystemOptions(baseUrl = "http://localhost:$appPort")
}
postgresql {
PostgresqlOptions(databaseName = "stove", configureExposedConfiguration = { cfg ->
listOf("spring.datasource.url=${cfg.jdbcUrl}")
})
}
kafka {
KafkaSystemOptions(configureExposedConfiguration = {
listOf("kafka.bootstrapServers=${it.bootstrapServers}")
})
}
springBoot(runner = { params -> run(params) { addTestSystemDependencies() } })
}.run()
override suspend fun afterProject() = Stove.stop()
}
Then write tests as usual — the dashboard captures everything automatically:
test("should create order and publish event") {
stove {
http {
postAndExpectBodilessResponse("/orders", body = CreateOrderRequest(orderId).some()) {
it.status shouldBe 201
}
}
kafka {
shouldBePublished<OrderCreatedEvent> {
actual.orderId == orderId
}
}
postgresql {
shouldQuery<Order>("SELECT * FROM orders WHERE id = '$orderId'") {
it.first().status shouldBe "CREATED"
}
}
}
}
Open http://localhost:4040 to see every HTTP request, Kafka message, database query, and distributed trace — in real time.
How It Relates to Reporting and Tracing¶
Dashboard, Reporting, and Tracing are complementary:
| Feature | Reporting | Tracing | Dashboard |
|---|---|---|---|
| When | On test failure | On test failure | Always (real-time) |
| Where | Console/CI output | Console/CI output | Browser UI |
| What | Test actions + assertions | Application call chain | Everything + history |
| Persistence | None (ephemeral) | None (ephemeral) | SQLite (across runs) |
Use all three together for the best experience:
- Reporting gives you immediate feedback in the terminal when something breaks
- Tracing gives you the execution trace and assertion DSL in your test code
- Dashboard gives you a browsable, persistent view of all test runs — successful and failed
Troubleshooting¶
Dashboard UI shows "Waiting for test events..."¶
- Verify the
stoveCLI is running:stove --version - Check that gRPC ports match: CLI default is
4041, Kotlin default is4041 - Look for connection errors in the CLI's terminal output
Tests run fine but nothing appears in Dashboard¶
- Ensure
dashboard {}is registered in your Stove config - Verify
stove-dashboardis in your test dependencies - Check that the CLI started before running tests
Dashboard works locally but not in CI¶
Dashboard is designed for local development. In CI, use Reporting and Tracing for failure diagnostics — they output to the console and don't require a running server.
Data from previous runs clutters the UI¶
This wipes the SQLite database and exits. Start the CLI again for a clean slate.
Database schema is corrupted or migrations fail¶
This backs up the existing database (printing the backup path), deletes it, and recreates a fresh one with all migrations applied. The servers start normally after — no need to run stove again.