From 2dbbf71e319fcbb5394cc6baa387f03c00f5b90d Mon Sep 17 00:00:00 2001 From: Austin Larson <78000745+alarso16@users.noreply.github.com> Date: Tue, 28 Oct 2025 09:25:28 -0400 Subject: [PATCH 1/5] test: Update rpc tests to reduce flake likelihood (ava-labs/coreth#1363) --- rpc/main_test.go | 51 ++++++++++++++++++++++++++ rpc/subscription_test.go | 8 ---- rpc/websocket_test.go | 79 ++++++++++++++++++---------------------- scripts/known_flakes.txt | 3 -- 4 files changed, 87 insertions(+), 54 deletions(-) create mode 100644 rpc/main_test.go diff --git a/rpc/main_test.go b/rpc/main_test.go new file mode 100644 index 0000000000..45579d92a7 --- /dev/null +++ b/rpc/main_test.go @@ -0,0 +1,51 @@ +// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +// +// This file is a derived work, based on the go-ethereum library whose original +// notices appear below. +// +// It is distributed under a license compatible with the licensing terms of the +// original code from which it is derived. +// +// Much love to the original authors for their work. +// ********** +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package rpc + +import ( + "os" + "testing" + + "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" +) + +func TestMain(m *testing.M) { + customtypes.Register() + + // Since there are so many flaky tests in the RPC package, we run the tests + // multiple times to try to get a passing run. + var code int + for range 5 { + code = m.Run() + if code == 0 { + break + } + } + + os.Exit(code) +} diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index 29020482b1..659d0328cb 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -35,22 +35,14 @@ import ( "io" "math/big" "net" - "os" "strings" "testing" "time" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/types" - - "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" ) -func TestMain(m *testing.M) { - customtypes.Register() - os.Exit(m.Run()) -} - func TestNewID(t *testing.T) { hexchars := "0123456789ABCDEFabcdef" for i := 0; i < 100; i++ { diff --git a/rpc/websocket_test.go b/rpc/websocket_test.go index c6d6c0a1d3..37c88241f7 100644 --- a/rpc/websocket_test.go +++ b/rpc/websocket_test.go @@ -134,56 +134,49 @@ func TestWebsocketLargeRead(t *testing.T) { srv = newTestServer() httpsrv = httptest.NewServer(srv.WebsocketHandler([]string{"*"})) wsURL = "ws:" + strings.TrimPrefix(httpsrv.URL, "http:") + buffer = 64 ) defer srv.Stop() defer httpsrv.Close() - testLimit := func(limit *int64) { - opts := []ClientOption{} - expLimit := int64(wsDefaultReadLimit) - if limit != nil && *limit >= 0 { - opts = append(opts, WithWebsocketMessageSizeLimit(*limit)) - if *limit > 0 { - expLimit = *limit // 0 means infinite + for _, tt := range []struct { + size int + limit int + err bool + }{ + {200, 200, false}, // Small, successful request and limit + {2048, 1024, true}, // Normal, failed request + {wsDefaultReadLimit + buffer, 0, false}, // Large, successful request, infinite limit + } { + func() { + if tt.limit != 0 { + // Some buffer is added to the limit to account for JSON encoding. It's + // skipped when the limit is zero since the intention is for the limit + // to be infinite. + tt.limit += buffer } - } - client, err := DialOptions(context.Background(), wsURL, opts...) - if err != nil { - t.Fatalf("can't dial: %v", err) - } - defer client.Close() - // Remove some bytes for json encoding overhead. - underLimit := int(expLimit - 128) - overLimit := expLimit + 1 - if expLimit == wsDefaultReadLimit { - // No point trying the full 32MB in tests. Just sanity-check that - // it's not obviously limited. - underLimit = 1024 - overLimit = -1 - } - var res string - // Check under limit - if err = client.Call(&res, "test_repeat", "A", underLimit); err != nil { - t.Fatalf("unexpected error with limit %d: %v", expLimit, err) - } - if len(res) != underLimit || strings.Count(res, "A") != underLimit { - t.Fatal("incorrect data") - } - // Check over limit - if overLimit > 0 { - err = client.Call(&res, "test_repeat", "A", expLimit+1) - if err == nil || err != websocket.ErrReadLimit { - t.Fatalf("wrong error with limit %d: %v expecting %v", expLimit, err, websocket.ErrReadLimit) + opts := []ClientOption{WithWebsocketMessageSizeLimit(int64(tt.limit))} + client, err := DialOptions(context.Background(), wsURL, opts...) + if err != nil { + t.Fatalf("failed to dial test server: %v", err) } - } - } - ptr := func(v int64) *int64 { return &v } + defer client.Close() - testLimit(ptr(-1)) // Should be ignored (use default) - testLimit(ptr(0)) // Should be ignored (use default) - testLimit(nil) // Should be ignored (use default) - testLimit(ptr(200)) - testLimit(ptr(wsDefaultReadLimit + 1024)) + var res string + err = client.Call(&res, "test_repeat", "A", tt.size) + if tt.err && err == nil { + t.Fatalf("expected error, got none") + } + if !tt.err { + if err != nil { + t.Fatalf("unexpected error with limit %d: %v", tt.limit, err) + } + if strings.Count(res, "A") != tt.size { + t.Fatal("incorrect data") + } + } + }() + } } func TestWebsocketPeerInfo(t *testing.T) { diff --git a/scripts/known_flakes.txt b/scripts/known_flakes.txt index 907cb9b42b..166ab5435f 100644 --- a/scripts/known_flakes.txt +++ b/scripts/known_flakes.txt @@ -1,6 +1,4 @@ TestChainIndexerWithChildren -TestClientCancelWebsocket -TestClientWebsocketLargeMessage TestGolangBindings TestMempoolEthTxsAppGossipHandling TestResumeSyncAccountsTrieInterrupted @@ -8,4 +6,3 @@ TestResyncNewRootAfterDeletes TestTransactionSkipIndexing TestVMShutdownWhileSyncing TestWaitDeployedCornerCases -TestWebsocketLargeRead \ No newline at end of file From 5be1f6b84f8f166a4eeae8211b797217d99b790c Mon Sep 17 00:00:00 2001 From: Austin Larson <78000745+alarso16@users.noreply.github.com> Date: Mon, 3 Nov 2025 17:55:48 -0500 Subject: [PATCH 2/5] test: Skip rpc tests that timeout (#1384) Signed-off-by: Austin Larson <78000745+alarso16@users.noreply.github.com> Co-authored-by: Stephen Buttolph --- rpc/websocket_test.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/rpc/websocket_test.go b/rpc/websocket_test.go index 37c88241f7..94db29e97e 100644 --- a/rpc/websocket_test.go +++ b/rpc/websocket_test.go @@ -89,9 +89,11 @@ func TestWebsocketOriginCheck(t *testing.T) { } // This test checks whether calls exceeding the request size limit are rejected. -/* +// +// This test times out occasionally due to context timeout differences with go-ethereum. +// These differences are not critical, so this test can simply be skipped. func TestWebsocketLargeCall(t *testing.T) { - t.Parallel() + t.Skip("Flaky") var ( srv = newTestServer() @@ -124,11 +126,13 @@ func TestWebsocketLargeCall(t *testing.T) { t.Fatal("no error for too large call") } } -*/ // This test checks whether the wsMessageSizeLimit option is obeyed. +// +// This test times out occasionally due to context timeout differences with go-ethereum. +// These differences are not critical, so this test can simply be skipped. func TestWebsocketLargeRead(t *testing.T) { - t.Parallel() + t.Skip("Flaky") var ( srv = newTestServer() From 46253c1ae2a78accaa6686f9ce13ffe7f5b6eb0e Mon Sep 17 00:00:00 2001 From: Austin Larson Date: Fri, 14 Nov 2025 14:25:52 -0500 Subject: [PATCH 3/5] fix: feedback --- rpc/main_test.go | 51 ---------------------------------------- rpc/subscription_test.go | 8 +++++++ rpc/websocket_test.go | 2 ++ 3 files changed, 10 insertions(+), 51 deletions(-) delete mode 100644 rpc/main_test.go diff --git a/rpc/main_test.go b/rpc/main_test.go deleted file mode 100644 index 45579d92a7..0000000000 --- a/rpc/main_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. -// -// This file is a derived work, based on the go-ethereum library whose original -// notices appear below. -// -// It is distributed under a license compatible with the licensing terms of the -// original code from which it is derived. -// -// Much love to the original authors for their work. -// ********** -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package rpc - -import ( - "os" - "testing" - - "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" -) - -func TestMain(m *testing.M) { - customtypes.Register() - - // Since there are so many flaky tests in the RPC package, we run the tests - // multiple times to try to get a passing run. - var code int - for range 5 { - code = m.Run() - if code == 0 { - break - } - } - - os.Exit(code) -} diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index 659d0328cb..29020482b1 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -35,14 +35,22 @@ import ( "io" "math/big" "net" + "os" "strings" "testing" "time" "github.com/ava-labs/libevm/common" "github.com/ava-labs/libevm/core/types" + + "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" ) +func TestMain(m *testing.M) { + customtypes.Register() + os.Exit(m.Run()) +} + func TestNewID(t *testing.T) { hexchars := "0123456789ABCDEFabcdef" for i := 0; i < 100; i++ { diff --git a/rpc/websocket_test.go b/rpc/websocket_test.go index 94db29e97e..40413064aa 100644 --- a/rpc/websocket_test.go +++ b/rpc/websocket_test.go @@ -94,6 +94,7 @@ func TestWebsocketOriginCheck(t *testing.T) { // These differences are not critical, so this test can simply be skipped. func TestWebsocketLargeCall(t *testing.T) { t.Skip("Flaky") + t.Parallel() var ( srv = newTestServer() @@ -133,6 +134,7 @@ func TestWebsocketLargeCall(t *testing.T) { // These differences are not critical, so this test can simply be skipped. func TestWebsocketLargeRead(t *testing.T) { t.Skip("Flaky") + t.Parallel() var ( srv = newTestServer() From 9e56ce5247cf5c46b8144ac83f53ac46e91cd457 Mon Sep 17 00:00:00 2001 From: Austin Larson Date: Fri, 21 Nov 2025 10:04:48 -0500 Subject: [PATCH 4/5] fix: revert changes to websocket test --- rpc/websocket_test.go | 79 +++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/rpc/websocket_test.go b/rpc/websocket_test.go index 40413064aa..ccb7f6a01d 100644 --- a/rpc/websocket_test.go +++ b/rpc/websocket_test.go @@ -140,49 +140,56 @@ func TestWebsocketLargeRead(t *testing.T) { srv = newTestServer() httpsrv = httptest.NewServer(srv.WebsocketHandler([]string{"*"})) wsURL = "ws:" + strings.TrimPrefix(httpsrv.URL, "http:") - buffer = 64 ) defer srv.Stop() defer httpsrv.Close() - for _, tt := range []struct { - size int - limit int - err bool - }{ - {200, 200, false}, // Small, successful request and limit - {2048, 1024, true}, // Normal, failed request - {wsDefaultReadLimit + buffer, 0, false}, // Large, successful request, infinite limit - } { - func() { - if tt.limit != 0 { - // Some buffer is added to the limit to account for JSON encoding. It's - // skipped when the limit is zero since the intention is for the limit - // to be infinite. - tt.limit += buffer + testLimit := func(limit *int64) { + opts := []ClientOption{} + expLimit := int64(wsDefaultReadLimit) + if limit != nil && *limit >= 0 { + opts = append(opts, WithWebsocketMessageSizeLimit(*limit)) + if *limit > 0 { + expLimit = *limit // 0 means infinite } - opts := []ClientOption{WithWebsocketMessageSizeLimit(int64(tt.limit))} - client, err := DialOptions(context.Background(), wsURL, opts...) - if err != nil { - t.Fatalf("failed to dial test server: %v", err) - } - defer client.Close() - - var res string - err = client.Call(&res, "test_repeat", "A", tt.size) - if tt.err && err == nil { - t.Fatalf("expected error, got none") - } - if !tt.err { - if err != nil { - t.Fatalf("unexpected error with limit %d: %v", tt.limit, err) - } - if strings.Count(res, "A") != tt.size { - t.Fatal("incorrect data") - } + } + client, err := DialOptions(context.Background(), wsURL, opts...) + if err != nil { + t.Fatalf("can't dial: %v", err) + } + defer client.Close() + // Remove some bytes for json encoding overhead. + underLimit := int(expLimit - 128) + overLimit := expLimit + 1 + if expLimit == wsDefaultReadLimit { + // No point trying the full 32MB in tests. Just sanity-check that + // it's not obviously limited. + underLimit = 1024 + overLimit = -1 + } + var res string + // Check under limit + if err = client.Call(&res, "test_repeat", "A", underLimit); err != nil { + t.Fatalf("unexpected error with limit %d: %v", expLimit, err) + } + if len(res) != underLimit || strings.Count(res, "A") != underLimit { + t.Fatal("incorrect data") + } + // Check over limit + if overLimit > 0 { + err = client.Call(&res, "test_repeat", "A", expLimit+1) + if err == nil || err != websocket.ErrReadLimit { + t.Fatalf("wrong error with limit %d: %v expecting %v", expLimit, err, websocket.ErrReadLimit) } - }() + } } + ptr := func(v int64) *int64 { return &v } + + testLimit(ptr(-1)) // Should be ignored (use default) + testLimit(ptr(0)) // Should be ignored (use default) + testLimit(nil) // Should be ignored (use default) + testLimit(ptr(200)) + testLimit(ptr(wsDefaultReadLimit + 1024)) } func TestWebsocketPeerInfo(t *testing.T) { From 02661f9ca2062f7109893426cc591bc7904fa1aa Mon Sep 17 00:00:00 2001 From: Austin Larson Date: Fri, 21 Nov 2025 13:05:01 -0500 Subject: [PATCH 5/5] new flake --- rpc/websocket_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rpc/websocket_test.go b/rpc/websocket_test.go index ccb7f6a01d..48073aea0f 100644 --- a/rpc/websocket_test.go +++ b/rpc/websocket_test.go @@ -277,7 +277,11 @@ func TestClientWebsocketPing(t *testing.T) { } // This checks that the websocket transport can deal with large messages. +// +// This test is upstream from go-ethereum but is skipped because it is flaky. +// Error message: call failed: websocket: close 1006 (abnormal closure): unexpected EOF func TestClientWebsocketLargeMessage(t *testing.T) { + t.Skip("Flaky") var ( srv = NewServer(0) httpsrv = httptest.NewServer(srv.WebsocketHandler(nil))