Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cmd/integration/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ func parseFlags(cfg *config.Config) error {
doNotCompareError := flag.Bool("E", false, "compare error code only, ignore error message")
flag.BoolVar(doNotCompareError, "do-not-compare-error", false, "compare error code only, ignore error message")

maxFailures := flag.Int("M", cfg.MaxFailures, "stop after this many failures, 0 = unlimited")
flag.IntVar(maxFailures, "max-failures", cfg.MaxFailures, "stop after this many failures, 0 = unlimited")

reportFile := flag.String("R", "", "write CSV summary report to file")
flag.StringVar(reportFile, "report-file", "", "write CSV summary report to file")

Expand Down Expand Up @@ -137,6 +140,7 @@ func parseFlags(cfg *config.Config) error {
cfg.WithoutCompareResults = *withoutCompare
cfg.DoNotCompareError = *doNotCompareError
cfg.TestsOnLatestBlock = *testOnLatest
cfg.MaxFailures = *maxFailures
cfg.ReportFile = *reportFile
cfg.CpuProfile = *cpuProfile
cfg.MemProfile = *memProfile
Expand Down Expand Up @@ -223,6 +227,7 @@ func usage() {
fmt.Println(" -w, --waiting-time <ms> wait time after test execution in milliseconds")
fmt.Println(" -S, --serial all tests run in serial way [default: parallel]")
fmt.Println(" -L, --tests-on-latest-block runs only test on latest block")
fmt.Println(" -M, --max-failures <n> stop after n failures, 0 = unlimited [default: 100]")
fmt.Println(" -R, --report-file <file> write summary report to file (.csv or .txt)")
fmt.Println(" --cpuprofile <file> write cpu profile to file")
fmt.Println(" --memprofile <file> write memory profile to file")
Expand Down
19 changes: 19 additions & 0 deletions integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Options:
-w, --waiting-time <ms> wait time after test execution in milliseconds
-S, --serial all tests run in serial way [default: parallel]
-L, --tests-on-latest-block runs only test on latest block
-M, --max-failures <n> stop after n failures, 0 = unlimited [default: 100]
-R, --report-file <file> write summary report to file (.csv or .txt)
--cpuprofile <file> write cpu profile to file
--memprofile <file> write memory profile to file
Expand Down Expand Up @@ -225,6 +226,24 @@ Number of success tests: 1188
Number of failed tests: 0
```

### Stop after too many failures

By default the runner stops after 100 failures to keep result artifacts small. Use `-M` to
override the limit or set it to `0` for unlimited:

```bash
# Stop after 50 failures (stricter than default)
./build/bin/rpc_int -c -f -M 50

# Run all tests regardless of failure count
./build/bin/rpc_int -c -f -M 0
```

When the limit is reached the runner prints:
```
ABORTED: too many failures (100), test sequence stopped early
```

### Run CI tests with Erigon

Assuming you have `erigon` installed beside `rpc-tests`:
Expand Down
4 changes: 4 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ type Config struct {
// Archive handling
SanitizeArchiveExt bool

// Failure cap
MaxFailures int // stop after this many failures (0 = unlimited)

// Report
ReportFile string

Expand Down Expand Up @@ -142,6 +145,7 @@ func NewConfig() *Config {
DiffKind: JsonDiffGo,
TransportType: TransportHTTP,
ResultsDir: ResultsDir,
MaxFailures: 100,
}
}

Expand Down
4 changes: 0 additions & 4 deletions internal/filter/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ func TestIsSkipped_DefaultList(t *testing.T) {
if !f.IsSkipped("engine_exchangeCapabilities", "engine_exchangeCapabilities/test_01.json", 2) {
t.Error("engine_ APIs should be skipped by default")
}
if !f.IsSkipped("trace_rawTransaction", "trace_rawTransaction/test_01.json", 3) {
t.Error("trace_rawTransaction should be skipped by default")
}

// Normal API should not be skipped
if f.IsSkipped("eth_call", "eth_call/test_01.json", 10) {
t.Error("eth_call should not be skipped by default")
Expand Down
17 changes: 16 additions & 1 deletion internal/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ func Run(ctx context.Context, cancelCtx context.CancelFunc, cfg *config.Config)
if cfg.ExitOnFail && stats.FailedTests > 0 {
return
}
if maxFailuresReached(cfg, stats) {
return
}
}
case <-ctx.Done():
return
Expand Down Expand Up @@ -296,12 +299,20 @@ func Run(ctx context.Context, cancelCtx context.CancelFunc, cfg *config.Config)
}
}

if maxFailuresReached(cfg, stats) {
fmt.Printf("\nABORTED: too many failures (%d), test sequence stopped early\n", cfg.MaxFailures)
}

if stats.FailedTests > 0 {
return 1, nil
}
return 0, nil
}

func maxFailuresReached(cfg *config.Config, stats *Stats) bool {
return cfg.MaxFailures > 0 && stats.FailedTests >= cfg.MaxFailures
}

func printResult(w *bufio.Writer, result *testdata.TestResult, stats *Stats, cfg *config.Config, cancelCtx context.CancelFunc, reportEntries *[]reportEntry, reportMu *sync.Mutex) {
file := fmt.Sprintf("%-60s", result.Test.Name)
tt := fmt.Sprintf("%-15s", result.Test.TransportType)
Expand Down Expand Up @@ -352,7 +363,11 @@ func printResult(w *bufio.Writer, result *testdata.TestResult, stats *Stats, cfg
})
reportMu.Unlock()
}
if cfg.ExitOnFail {
if maxFailuresReached(cfg, stats) {
fmt.Fprintf(w, "\nABORTED: too many failures (%d), test sequence stopped early\n", cfg.MaxFailures)
w.Flush()
cancelCtx()
} else if cfg.ExitOnFail {
w.Flush()
cancelCtx()
}
Expand Down
91 changes: 91 additions & 0 deletions internal/runner/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,97 @@ func TestCheckTestNameForNumber(t *testing.T) {
}
}

func TestMaxFailures_StopsAfterLimit(t *testing.T) {
const maxFail = 3
const totalTests = 10

cfg := config.NewConfig()
cfg.ExitOnFail = false
cfg.MaxFailures = maxFail

var buf bytes.Buffer
w := bufio.NewWriter(&buf)
stats := &Stats{}
var entries []reportEntry
var mu sync.Mutex

ctxCancelled := false
cancelWrapper := func() {
ctxCancelled = true
}

for i := range totalTests {
r := testdata.TestResult{
Outcome: testdata.TestOutcome{Success: false, Error: fmt.Errorf("connection refused")},
Test: &testdata.TestDescriptor{
Name: "eth_call/test_01.json",
Number: i + 1,
TransportType: "http",
Index: i,
},
}
printResult(w, &r, stats, cfg, cancelWrapper, &entries, &mu)
if ctxCancelled {
break
}
}
w.Flush()

if stats.FailedTests != maxFail {
t.Errorf("FailedTests: got %d, want %d", stats.FailedTests, maxFail)
}
if !ctxCancelled {
t.Error("cancelCtx should have been called when MaxFailures reached")
}
output := buf.String()
if !strings.Contains(output, "ABORTED") {
t.Errorf("expected ABORTED message in output, got:\n%s", output)
}
if !strings.Contains(output, fmt.Sprintf("%d", maxFail)) {
t.Errorf("expected failure count %d in abort message, got:\n%s", maxFail, output)
}
}

func TestMaxFailures_ZeroMeansUnlimited(t *testing.T) {
const totalTests = 10

cfg := config.NewConfig()
cfg.ExitOnFail = false
cfg.MaxFailures = 0 // unlimited

var buf bytes.Buffer
w := bufio.NewWriter(&buf)
stats := &Stats{}
var entries []reportEntry
var mu sync.Mutex

ctxCancelled := false
cancelWrapper := func() {
ctxCancelled = true
}

for i := range totalTests {
r := testdata.TestResult{
Outcome: testdata.TestOutcome{Success: false, Error: fmt.Errorf("connection refused")},
Test: &testdata.TestDescriptor{
Name: "eth_call/test_01.json",
Number: i + 1,
TransportType: "http",
Index: i,
},
}
printResult(w, &r, stats, cfg, cancelWrapper, &entries, &mu)
}
w.Flush()

if ctxCancelled {
t.Error("cancelCtx should NOT be called when MaxFailures=0 (unlimited)")
}
if stats.FailedTests != totalTests {
t.Errorf("FailedTests: got %d, want %d", stats.FailedTests, totalTests)
}
}

func TestPrintResult_OrderedOutput(t *testing.T) {
const numTests = 50

Expand Down