-
Notifications
You must be signed in to change notification settings - Fork 214
[Testing] Add regression tests for network data race fixes #8635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
janezpodhostnik
wants to merge
1
commit into
janez/fix-flaky-unit-tests-batch-2
Choose a base branch
from
janez/flaky-test-regression-coverage-network
base: janez/fix-flaky-unit-tests-batch-2
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package scoring | ||
|
|
||
| import ( | ||
| "testing" | ||
| "time" | ||
|
|
||
| "github.com/stretchr/testify/require" | ||
| "go.uber.org/atomic" | ||
| ) | ||
|
|
||
| // TestAfterSilencePeriod verifies the state machine of the scoring registry's startup silence | ||
| // period, in particular that the silence period does not end before the registry has started. | ||
| // Regression: the start time used to be a plain time.Time (a data race with the startup worker), | ||
| // and its zero value made time.Since(zero) exceed any configured duration, spuriously ending the | ||
| // silence period if the score function was queried before startup. | ||
| func TestAfterSilencePeriod(t *testing.T) { | ||
| reg := &GossipSubAppSpecificScoreRegistry{ | ||
| silencePeriodDuration: time.Hour, | ||
| silencePeriodStartTime: atomic.NewPointer[time.Time](nil), | ||
| silencePeriodElapsed: atomic.NewBool(false), | ||
| } | ||
|
|
||
| // before startup (start time not set), the silence period has not even begun | ||
| require.False(t, reg.afterSilencePeriod()) | ||
|
|
||
| // silence period started, but not yet over | ||
| now := time.Now() | ||
| reg.silencePeriodStartTime.Store(&now) | ||
| require.False(t, reg.afterSilencePeriod()) | ||
|
|
||
| // silence period over | ||
| past := time.Now().Add(-2 * time.Hour) | ||
| reg.silencePeriodStartTime.Store(&past) | ||
| require.True(t, reg.afterSilencePeriod()) | ||
|
|
||
| // once elapsed, the silence period stays elapsed | ||
| require.True(t, reg.silencePeriodElapsed.Load()) | ||
| require.True(t, reg.afterSilencePeriod()) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| package slashing_test | ||
|
|
||
| import ( | ||
| "errors" | ||
| "sync" | ||
| "testing" | ||
| "time" | ||
|
|
||
| "github.com/stretchr/testify/mock" | ||
| "github.com/stretchr/testify/require" | ||
|
|
||
| "github.com/onflow/flow-go/model/flow" | ||
| mockmodule "github.com/onflow/flow-go/module/mock" | ||
| "github.com/onflow/flow-go/network" | ||
| "github.com/onflow/flow-go/network/channels" | ||
| "github.com/onflow/flow-go/network/message" | ||
| mocknetwork "github.com/onflow/flow-go/network/mock" | ||
| "github.com/onflow/flow-go/network/slashing" | ||
| "github.com/onflow/flow-go/utils/unittest" | ||
| ) | ||
|
|
||
| // newConsumerFixture returns a slashing violations consumer whose metrics and misbehavior | ||
| // report consumer tolerate any number of calls. | ||
| func newConsumerFixture(t *testing.T) *slashing.Consumer { | ||
| metrics := mockmodule.NewNetworkSecurityMetrics(t) | ||
| metrics.On("OnUnauthorizedMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return().Maybe() | ||
| metrics.On("OnViolationReportSkipped").Return().Maybe() | ||
|
|
||
| misbehaviorReportConsumer := mocknetwork.NewMisbehaviorReportConsumer(t) | ||
| misbehaviorReportConsumer.On("ReportMisbehaviorOnChannel", mock.Anything, mock.Anything).Return().Maybe() | ||
|
|
||
| return slashing.NewSlashingViolationsConsumer(unittest.Logger(), metrics, misbehaviorReportConsumer) | ||
| } | ||
|
|
||
| // violationFixture returns a violation without an identity (a violation from an unknown peer) | ||
| // and without a message type (a violation raised before the message could be decoded). | ||
| func violationFixture() *network.Violation { | ||
| return &network.Violation{ | ||
| Identity: nil, | ||
| PeerID: "peer-id", | ||
| OriginID: flow.ZeroID, | ||
| MsgType: "", // simulates a violation raised before the message type is known | ||
| Channel: channels.TestNetworkChannel, | ||
| Protocol: message.ProtocolTypeUnicast, | ||
| Err: errors.New("unauthorized"), | ||
| } | ||
| } | ||
|
|
||
| // TestConsumer_DoesNotMutateViolation is a regression test verifying that the consumer never | ||
| // mutates the violation passed to it: callers may share one violation object across goroutines | ||
| // (or reuse it for multiple notifications), so an in-place default (e.g. setting MsgType to | ||
| // "unknown") would be a data race and would leak into subsequent uses. | ||
| func TestConsumer_DoesNotMutateViolation(t *testing.T) { | ||
| consumer := newConsumerFixture(t) | ||
|
|
||
| violation := violationFixture() | ||
| consumer.OnUnauthorizedSenderError(violation) | ||
|
|
||
| require.Empty(t, violation.MsgType, "consumer must not mutate the violation's MsgType") | ||
| require.Nil(t, violation.Identity, "consumer must not mutate the violation's Identity") | ||
| } | ||
|
|
||
| // TestConsumer_ConcurrentNotifications is a regression test verifying that a single violation | ||
| // object can be reported concurrently through all consumer entry points without a data race | ||
| // (run with -race). Before the fix, logOffense wrote a default MsgType into the shared | ||
| // violation, racing the reads of concurrent notifications. | ||
| func TestConsumer_ConcurrentNotifications(t *testing.T) { | ||
| consumer := newConsumerFixture(t) | ||
|
|
||
| violation := violationFixture() | ||
|
|
||
| notify := []func(*network.Violation){ | ||
| consumer.OnUnauthorizedSenderError, | ||
| consumer.OnUnknownMsgTypeError, | ||
| consumer.OnInvalidMsgError, | ||
| consumer.OnSenderEjectedError, | ||
| consumer.OnUnauthorizedUnicastOnChannel, | ||
| consumer.OnUnauthorizedPublishOnChannel, | ||
| } | ||
|
|
||
| workers := 4 | ||
| iterations := 50 | ||
| var wg sync.WaitGroup | ||
| wg.Add(workers) | ||
| for range workers { | ||
| go func() { | ||
| defer wg.Done() | ||
| for i := 0; i < iterations; i++ { | ||
| notify[i%len(notify)](violation) | ||
| } | ||
| }() | ||
| } | ||
| unittest.RequireReturnsBefore(t, wg.Wait, 10*time.Second, "concurrent notifications did not finish on time") | ||
|
|
||
| require.Empty(t, violation.MsgType, "consumer must not mutate the violation's MsgType") | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use
WaitGroup.Gofor new code instead of the manual dance