Skip to content

Commit ed8beec

Browse files
authored
Add support for stateful test suites and add chain tests (#11)
This PR introduces stateful test suites and adds a new suite for testing chain operations. **Key additions:** - **Stateful suite support**: Introduces a stateful flag for test suites where tests depend on each other's success. If any test fails in a stateful suite, all subsequent tests are automatically skipped and marked as failed. Handler processes are respawned after stateful suites to prevent state leaks between suites. - **Object reference protocol**: Implements ref field and introduces registry pattern for persisting objects (contexts, blocks, etc.) across requests, enabling complex multi-step test scenarios. - **Chain operations test suite**: New `chain.json` demonstrates stateful testing with block processing, height tracking, and chain reorganization verification. The block data used in this suite can be deterministically regenerated by [this](https://github.com/stringintech/bitcoin/blob/653b99b674ec53fa3b1f9b9a2a7727b9c92644be/test/functional/example_regtest_reorg.py) functional test. - **Method reference documentation**: Restructures `handler-spec.md` with detailed method reference for all supported operations. - **Verbose mode**: Adds `-v` and `-vv` flags to print complete request chains that can be piped directly to a handler for manual debugging and reproduction - #6.
2 parents e852f43 + a5976bb commit ed8beec

12 files changed

Lines changed: 1426 additions & 63 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ test:
2222
@echo "Running runner unit tests..."
2323
go test -v ./runner/...
2424
@echo "Running conformance tests with mock handler..."
25-
$(RUNNER_BIN) -handler $(MOCK_HANDLER_BIN)
25+
$(RUNNER_BIN) --handler $(MOCK_HANDLER_BIN) -vv
2626

2727
clean:
2828
@echo "Cleaning build artifacts..."

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,33 @@ make runner
6666

6767
The runner automatically detects and recovers from crashed/unresponsive handlers, allowing remaining tests to continue.
6868

69+
#### Verbose Flags
70+
71+
- **`-v, --verbose`**: Shows request chains and responses for **failed tests only**
72+
- **`-vv`**: Shows request chains and responses for **all tests** (passed and failed)
73+
74+
The request chains printed by verbose mode can be directly piped to the handler binary for manual debugging:
75+
76+
```bash
77+
# Example output from -vv mode:
78+
# ✓ chain#4 (Get active chain reference from chainstate manager)
79+
#
80+
# Request chain
81+
# ────────────────────────────────────────
82+
# {"id":"chain#1","method":"btck_context_create","params":{"chain_parameters":{"chain_type":"btck_ChainType_REGTEST"}},"ref":"$context_ref"}
83+
# {"id":"chain#2","method":"btck_chainstate_manager_create","params":{"context":"$context_ref"},"ref":"$chainstate_manager_ref"}
84+
# {"id":"chain#4","method":"btck_chainstate_manager_get_active_chain","params":{"chainstate_manager":"$chainstate_manager_ref"},"ref":"$chain_ref"}
85+
#
86+
# Response:
87+
# ────────────────────────────────────────
88+
# {"result":"$chain_ref"}
89+
90+
# Copy the request chain and pipe it to your handler for debugging:
91+
echo '{"id":"chain#1","method":"btck_context_create","params":{"chain_parameters":{"chain_type":"btck_ChainType_REGTEST"}},"ref":"$context_ref"}
92+
{"id":"chain#2","method":"btck_chainstate_manager_create","params":{"context":"$context_ref"},"ref":"$chainstate_manager_ref"}
93+
{"id":"chain#4","method":"btck_chainstate_manager_get_active_chain","params":{"chainstate_manager":"$chainstate_manager_ref"},"ref":"$chain_ref"}' | ./path/to/your/handler
94+
```
95+
6996
### Testing the Runner
7097

7198
Build and test the runner:

cmd/runner/main.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,36 @@ package main
22

33
import (
44
"context"
5-
"flag"
65
"fmt"
76
"io/fs"
87
"os"
8+
"sort"
99
"strings"
1010
"time"
1111

12+
"github.com/spf13/pflag"
1213
"github.com/stringintech/kernel-bindings-tests/runner"
1314
"github.com/stringintech/kernel-bindings-tests/testdata"
1415
)
1516

1617
func main() {
17-
handlerPath := flag.String("handler", "", "Path to handler binary")
18-
handlerTimeout := flag.Duration("handler-timeout", 10*time.Second, "Max time to wait for handler to respond to each test case (e.g., 10s, 500ms)")
19-
timeout := flag.Duration("timeout", 30*time.Second, "Total timeout for executing all test suites (e.g., 30s, 1m)")
20-
flag.Parse()
18+
handlerPath := pflag.String("handler", "", "Path to handler binary")
19+
handlerTimeout := pflag.Duration("handler-timeout", 10*time.Second, "Max time to wait for handler to respond to each test case (e.g., 10s, 500ms)")
20+
timeout := pflag.Duration("timeout", 30*time.Second, "Total timeout for executing all test suites (e.g., 30s, 1m)")
21+
verboseCount := pflag.CountP("verbose", "v", "Verbose mode: -v shows all requests needed to reproduce failed tests, plus received/expected responses; -vv shows this for all tests (passed and failed)")
22+
pflag.Parse()
23+
24+
// Convert verbose count to verbosity level
25+
verbosity := runner.VerbosityQuiet
26+
if *verboseCount >= 2 {
27+
verbosity = runner.VerbosityAlways
28+
} else if *verboseCount == 1 {
29+
verbosity = runner.VerbosityOnFailure
30+
}
2131

2232
if *handlerPath == "" {
23-
fmt.Fprintf(os.Stderr, "Error: -handler flag is required\n")
24-
flag.Usage()
33+
fmt.Fprintf(os.Stderr, "Error: --handler flag is required\n")
34+
pflag.Usage()
2535
os.Exit(1)
2636
}
2737

@@ -37,6 +47,9 @@ func main() {
3747
os.Exit(1)
3848
}
3949

50+
// Sort test files alphabetically for deterministic execution order
51+
sort.Strings(testFiles)
52+
4053
// Create test runner
4154
testRunner, err := runner.NewTestRunner(*handlerPath, *handlerTimeout, *timeout)
4255
if err != nil {
@@ -65,12 +78,18 @@ func main() {
6578
}
6679

6780
// Run suite
68-
result := testRunner.RunTestSuite(ctx, *suite)
81+
result := testRunner.RunTestSuite(ctx, *suite, verbosity)
6982
printResults(suite, result)
7083

7184
totalPassed += result.PassedTests
7285
totalFailed += result.FailedTests
7386
totalTests += result.TotalTests
87+
88+
// Close handler after stateful suites to prevent state leaks.
89+
// A new handler process will be spawned on-demand when the next request is sent.
90+
if suite.Stateful {
91+
testRunner.CloseHandler()
92+
}
7493
}
7594

7695
fmt.Printf("\n" + strings.Repeat("=", 60) + "\n")

0 commit comments

Comments
 (0)