Skip to content

Commit 1bd347e

Browse files
committed
Merge branch 'main' of github.com:smartcontractkit/chainlink-testing-framework into useParrot
2 parents d35c59d + de11cba commit 1bd347e

File tree

12 files changed

+1434
-40
lines changed

12 files changed

+1434
-40
lines changed

seth/.changeset/v1.51.1.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Use more conservative gas tip estimation, i.e. call `FeeHistory` endpoint with tip percentile corresponding to given priory and then select median value

seth/gas_adjuster.go

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -504,38 +504,58 @@ func classifyCongestion(congestionMetric float64) string {
504504
}
505505

506506
func (m *Client) HistoricalFeeData(priority string) (baseFee float64, historicalGasTipCap float64, err error) {
507+
var percentileTip float64
508+
509+
// based on priority decide, which percentile to use to get historical tip values, when calling FeeHistory
510+
switch priority {
511+
case Priority_Degen:
512+
percentileTip = 100
513+
case Priority_Fast:
514+
percentileTip = 99
515+
case Priority_Standard:
516+
percentileTip = 50
517+
case Priority_Slow:
518+
percentileTip = 25
519+
default:
520+
err = fmt.Errorf("unknown priority: %s", priority)
521+
L.Debug().
522+
Str("Priority", priority).
523+
Msgf("Unknown priority: %s", err.Error())
524+
525+
return
526+
}
527+
507528
estimator := NewGasEstimator(m)
508-
stats, err := estimator.Stats(m.Cfg.Network.GasPriceEstimationBlocks, 99)
529+
stats, err := estimator.Stats(m.Cfg.Network.GasPriceEstimationBlocks, percentileTip)
509530
if err != nil {
510531
L.Debug().
511532
Msgf("Failed to get fee history due to: %s", err.Error())
512533

513534
return
514535
}
515536

537+
// base fee should still be based on priority, because FeeHistory returns whole base fee history, not just the requested percentile
516538
switch priority {
517539
case Priority_Degen:
518540
baseFee = stats.GasPrice.Max
519-
historicalGasTipCap = stats.TipCap.Max
520541
case Priority_Fast:
521542
baseFee = stats.GasPrice.Perc99
522-
historicalGasTipCap = stats.TipCap.Perc99
523543
case Priority_Standard:
524544
baseFee = stats.GasPrice.Perc50
525-
historicalGasTipCap = stats.TipCap.Perc50
526545
case Priority_Slow:
527546
baseFee = stats.GasPrice.Perc25
528-
historicalGasTipCap = stats.TipCap.Perc25
529547
default:
530548
err = fmt.Errorf("unknown priority: %s", priority)
531549
L.Debug().
532550
Str("Priority", priority).
533551
Msgf("Unknown priority: %s", err.Error())
534552

535553
return
536-
537554
}
538555

556+
// since we have already requested reward percentiles based on priority, let's now use the median, i.e. most common tip
557+
historicalGasTipCap = stats.TipCap.Perc50
558+
539559
return
540560
}
541561

seth/gas_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ func TestGasEstimator(t *testing.T) {
1313
c := newClient(t)
1414
bn, err := c.Client.BlockNumber(context.Background())
1515
require.NoError(t, err, "BlockNumber should not error")
16-
for i := 0; i < 10; i++ {
16+
for range 10 {
1717
_, err := c.DeployContractFromContractStore(c.NewTXOpts(), "NetworkDebugSubContract")
1818
require.NoError(t, err, "Deploying contract should not error")
1919
}

seth/seth.toml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ root_key_funds_buffer = 10 # 10 ether
4949

5050
# feature-flagged expriments; first one sets funds return priority to 'slow' (core only!), second one
5151
# sets the tip/base fee to the higher value in case there's 3+ orders of magnitude difference between them
52-
experiments_enabled = ["slow_funds_return", "eip_1559_fee_equalizer"]
52+
# experiments_enabled = ["slow_funds_return", "eip_1559_fee_equalizer"]
5353

5454
# when enabled when creating a new Seth client we will send 10k wei from root address to root address
5555
# to make sure transaction can be submitted and mined
@@ -81,6 +81,32 @@ key_sync_retries = 10
8181
[block_stats]
8282
rpc_requests_per_second_limit = 15
8383

84+
[[networks]]
85+
name = "Ethereum_Mainnet"
86+
dial_timeout = "1m"
87+
transaction_timeout = "30s"
88+
eip_1559_dynamic_fees = true
89+
90+
# automated gas estimation
91+
gas_price_estimation_enabled = true
92+
gas_price_estimation_blocks = 20
93+
gas_price_estimation_tx_priority = "standard"
94+
# how many times to try fetching & calculating gas price data in case of errors, defaults to 1 if empty
95+
gas_price_estimation_attempt_count = 2
96+
# urls_secret = ["xxx"]
97+
98+
# gas limits
99+
transfer_gas_fee = 21_000
100+
# gas limit should be explicitly set only if you are connecting to a node that's incapable of estimating gas limit itself (should only happen for very old versions)
101+
# gas_limit = 14_000_000
102+
103+
# manual settings, used when gas_price_estimation_enabled is false or when it fails
104+
# legacy transactions
105+
gas_price = 1_000_000_000
106+
# EIP-1559 transactions
107+
gas_fee_cap = 25_000_000_000
108+
gas_tip_cap = 5_000_000_000
109+
84110
[[networks]]
85111
name = "Anvil"
86112
dial_timeout = "1m"

tools/flakeguard/cmd/run.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ var RunTestsCmd = &cobra.Command{
4141
useShuffle, _ := cmd.Flags().GetBool("shuffle")
4242
shuffleSeed, _ := cmd.Flags().GetString("shuffle-seed")
4343
omitOutputsOnSuccess, _ := cmd.Flags().GetBool("omit-test-outputs-on-success")
44+
ignoreParentFailuresOnSubtests, _ := cmd.Flags().GetBool("ignore-parent-failures-on-subtests")
4445

4546
outputDir := filepath.Dir(outputPath)
4647
initialDirSize, err := getDirSize(outputDir)
@@ -63,7 +64,6 @@ var RunTestsCmd = &cobra.Command{
6364
// Determine test packages
6465
var testPackages []string
6566
if len(testCmdStrings) == 0 {
66-
// No custom command -> parse packages
6767
if testPackagesJson != "" {
6868
if err := json.Unmarshal([]byte(testPackagesJson), &testPackages); err != nil {
6969
log.Error().Err(err).Msg("Error decoding test packages JSON")
@@ -79,18 +79,19 @@ var RunTestsCmd = &cobra.Command{
7979

8080
// Initialize the runner
8181
testRunner := runner.Runner{
82-
ProjectPath: projectPath,
83-
Verbose: true,
84-
RunCount: runCount,
85-
Timeout: timeout,
86-
Tags: tags,
87-
UseRace: useRace,
88-
SkipTests: skipTests,
89-
SelectTests: selectTests,
90-
UseShuffle: useShuffle,
91-
ShuffleSeed: shuffleSeed,
92-
OmitOutputsOnSuccess: omitOutputsOnSuccess,
93-
MaxPassRatio: maxPassRatio,
82+
ProjectPath: projectPath,
83+
Verbose: true,
84+
RunCount: runCount,
85+
Timeout: timeout,
86+
Tags: tags,
87+
UseRace: useRace,
88+
SkipTests: skipTests,
89+
SelectTests: selectTests,
90+
UseShuffle: useShuffle,
91+
ShuffleSeed: shuffleSeed,
92+
OmitOutputsOnSuccess: omitOutputsOnSuccess,
93+
MaxPassRatio: maxPassRatio,
94+
IgnoreParentFailuresOnSubtests: ignoreParentFailuresOnSubtests,
9495
}
9596

9697
// Run the tests
@@ -105,7 +106,6 @@ var RunTestsCmd = &cobra.Command{
105106
os.Exit(ErrorExitCode)
106107
}
107108
} else {
108-
// Otherwise, use the normal go test approach
109109
testReport, err = testRunner.RunTestPackages(testPackages)
110110
if err != nil {
111111
log.Fatal().Err(err).Msg("Error running test packages")
@@ -180,6 +180,7 @@ func init() {
180180
RunTestsCmd.Flags().StringSlice("select-tests", nil, "Comma-separated list of test names to specifically run")
181181
RunTestsCmd.Flags().Float64("max-pass-ratio", 1.0, "The maximum pass ratio threshold for a test to be considered flaky. Any tests below this pass rate will be considered flaky.")
182182
RunTestsCmd.Flags().Bool("omit-test-outputs-on-success", true, "Omit test outputs and package outputs for tests that pass")
183+
RunTestsCmd.Flags().Bool("ignore-parent-failures-on-subtests", false, "Ignore failures in parent tests when only subtests fail")
183184
}
184185

185186
func checkDependencies(projectPath string) error {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Go Test Transform
2+
3+
This utility transforms the output of Go's test JSON format to handle subtest failures more intelligently. It prevents parent tests from failing when only their subtests fail, while preserving the original test structure and output format.
4+
5+
## Features
6+
7+
- Transforms Go test JSON output to modify how test failures propagate
8+
- Parent tests won't fail if they only have failing subtests but no direct failures
9+
- Maintains the original JSON format for compatibility with other tools
10+
11+
## Key Behavior
12+
13+
- **Subtest Failure Handling**: When a subtest fails, the parent test will not be marked as failed unless the parent itself has a direct failure
14+
- **Important Note**: If a parent test has both log messages (`t.Log()`) and failing subtests, it will still be marked as failed, as seen in the `TestLogMessagesNotDirectFailures` test
15+
16+
## Usage
17+
18+
```bash
19+
go test -json ./... | go-test-transform -ignore-all
20+
```
21+
22+
This will transform the test output to prevent parent tests from failing when only their subtests fail.
23+
24+
## Options
25+
26+
- `-ignore-all`: Ignore all subtest failures
27+
- `-input`: Input file (default: stdin)
28+
- `-output`: Output file (default: stdout)
29+
30+
## Example
31+
32+
For a test structure like:
33+
34+
```go
35+
func TestParent(t *testing.T) {
36+
t.Run("Subtest1", func(t *testing.T) {
37+
t.Error("Subtest 1 failed")
38+
})
39+
}
40+
```
41+
42+
The transformed output will be:
43+
44+
```json
45+
{"Time":"2023-05-10T15:04:05.123Z","Action":"run","Package":"example/pkg","Test":"TestParent"}
46+
{"Time":"2023-05-10T15:04:05.124Z","Action":"run","Package":"example/pkg","Test":"TestParent/Subtest1"}
47+
{"Time":"2023-05-10T15:04:05.125Z","Action":"output","Package":"example/pkg","Test":"TestParent/Subtest1","Output":" subtest1_test.go:12: Subtest 1 failed\n"}
48+
{"Time":"2023-05-10T15:04:05.126Z","Action":"fail","Package":"example/pkg","Test":"TestParent/Subtest1","Elapsed":0.001}
49+
{"Time":"2023-05-10T15:04:05.127Z","Action":"pass","Package":"example/pkg","Test":"TestParent","Elapsed":0.004}
50+
{"Time":"2023-05-10T15:04:05.128Z","Action":"output","Package":"example/pkg","Output":"FAIL\texample/pkg\t0.004s\n"}
51+
{"Time":"2023-05-10T15:04:05.129Z","Action":"fail","Package":"example/pkg","Elapsed":0.005}
52+
```
53+
54+
Note that in the original output, both `TestParent/Subtest1` and `TestParent` would be marked as failed. After transformation, `TestParent/Subtest1` remains failed, but `TestParent` is changed to pass since it doesn't have a direct failure.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"io"
7+
"os"
8+
9+
"github.com/smartcontractkit/chainlink-testing-framework/tools/flakeguard/go-test-transform/pkg/transformer"
10+
)
11+
12+
func main() {
13+
// Parse command-line flags
14+
var (
15+
ignoreAll bool
16+
inputFile string
17+
outputFile string
18+
)
19+
20+
flag.BoolVar(&ignoreAll, "ignore-all", false, "Ignore all subtest failures")
21+
flag.StringVar(&inputFile, "input", "", "Input JSON file (if not provided, reads from stdin)")
22+
flag.StringVar(&outputFile, "output", "", "File to write the report to (default: stdout)")
23+
flag.Parse()
24+
25+
// Set up options
26+
opts := transformer.NewOptions(ignoreAll)
27+
28+
// Determine input source
29+
var input io.Reader
30+
if inputFile != "" {
31+
// Read from file
32+
file, err := os.Open(inputFile)
33+
if err != nil {
34+
fmt.Fprintf(os.Stderr, "Error opening input file: %v\n", err)
35+
os.Exit(1)
36+
}
37+
defer file.Close()
38+
input = file
39+
} else {
40+
// Read from stdin
41+
input = os.Stdin
42+
}
43+
44+
// Determine output destination
45+
var output io.Writer
46+
if outputFile != "" {
47+
// Write to file
48+
file, err := os.Create(outputFile)
49+
if err != nil {
50+
fmt.Fprintf(os.Stderr, "Error creating output file: %v\n", err)
51+
os.Exit(1)
52+
}
53+
defer file.Close()
54+
output = file
55+
} else {
56+
// Write to stdout
57+
output = os.Stdout
58+
}
59+
60+
// Transform the output
61+
err := transformer.TransformJSON(input, output, opts)
62+
if err != nil {
63+
fmt.Fprintf(os.Stderr, "Error transforming JSON: %v\n", err)
64+
os.Exit(1)
65+
}
66+
67+
// Exit with the appropriate code
68+
os.Exit(0)
69+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package transformer
2+
3+
// Options defines configuration options for the test transformer
4+
type Options struct {
5+
// IgnoreAllSubtestFailures determines if all subtest failures should be ignored
6+
IgnoreAllSubtestFailures bool
7+
}
8+
9+
// DefaultOptions returns a new Options with default values
10+
func DefaultOptions() *Options {
11+
return &Options{
12+
IgnoreAllSubtestFailures: false,
13+
}
14+
}
15+
16+
// NewOptions creates a new Options with the specified parameters
17+
func NewOptions(ignoreAll bool) *Options {
18+
return &Options{
19+
IgnoreAllSubtestFailures: ignoreAll,
20+
}
21+
}

0 commit comments

Comments
 (0)