-
Notifications
You must be signed in to change notification settings - Fork 471
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
network: Ignore invalid tags #4517
Changes from all commits
0346b11
0b0f37c
0e2fe4c
1b5595b
9df1d0c
06f5c56
bfb3ca1
ce2af33
5e04cb8
b7719f7
0e702e4
18ace9d
ccd5f37
0c6f169
936e568
5f0cd15
c91c1a4
ceba110
12dbc02
a7dd7a7
0346817
e390c9a
4fbc0f6
4a780fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,12 +19,18 @@ package network | |
import ( | ||
"encoding/binary" | ||
"fmt" | ||
"go/ast" | ||
"go/parser" | ||
"go/token" | ||
"path/filepath" | ||
"sort" | ||
"strings" | ||
"testing" | ||
"time" | ||
"unsafe" | ||
|
||
"github.com/algorand/go-algorand/logging" | ||
"github.com/algorand/go-algorand/protocol" | ||
"github.com/algorand/go-algorand/test/partitiontest" | ||
"github.com/algorand/go-algorand/util/metrics" | ||
"github.com/stretchr/testify/require" | ||
|
@@ -104,6 +110,11 @@ func TestAtomicVariablesAlignment(t *testing.T) { | |
require.True(t, (unsafe.Offsetof(p.lastPacketTime)%8) == 0) | ||
require.True(t, (unsafe.Offsetof(p.intermittentOutgoingMessageEnqueueTime)%8) == 0) | ||
require.True(t, (unsafe.Offsetof(p.duplicateFilterCount)%8) == 0) | ||
require.True(t, (unsafe.Offsetof(p.txMessageCount)%8) == 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is great and why don't we have this for everything we There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. looks like can be done as a custom linter similar to part test, by using fieldalignment as an example There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried the fieldalignment linter and it didn't work ... it requires being run on a 32-bit platform to work (!!) and I even tried it using a 32-bit docker image inside qemu and it didn't catch everything. However in Go 1.19 we can switch to the new automatically aligned atomic types and not need to worry about this anymore. |
||
require.True(t, (unsafe.Offsetof(p.miMessageCount)%8) == 0) | ||
require.True(t, (unsafe.Offsetof(p.ppMessageCount)%8) == 0) | ||
require.True(t, (unsafe.Offsetof(p.avMessageCount)%8) == 0) | ||
require.True(t, (unsafe.Offsetof(p.unkMessageCount)%8) == 0) | ||
} | ||
|
||
func TestTagCounterFiltering(t *testing.T) { | ||
|
@@ -180,3 +191,91 @@ func TestVersionToFeature(t *testing.T) { | |
}) | ||
} | ||
} | ||
|
||
func TestPeerReadLoopSwitchAllTags(t *testing.T) { | ||
partitiontest.PartitionTest(t) | ||
t.Parallel() | ||
|
||
allTags := getProtocolTags(t) | ||
foundTags := []string{} | ||
|
||
fset := token.NewFileSet() | ||
f, err := parser.ParseFile(fset, "wsPeer.go", nil, 0) | ||
require.NoError(t, err) | ||
|
||
getCases := func(n ast.Node) (ret bool) { | ||
switch x := n.(type) { | ||
case *ast.SwitchStmt: | ||
// look for "switch msg.Tag" | ||
if tagSel, ok := x.Tag.(*ast.SelectorExpr); ok { | ||
if tagSel.Sel.Name != "Tag" { | ||
return false | ||
} | ||
if id, ok := tagSel.X.(*ast.Ident); ok && id.Name != "msg" { | ||
return false | ||
} | ||
} | ||
// found switch msg.Tag, go through case statements | ||
for _, s := range x.Body.List { | ||
cl, ok := s.(*ast.CaseClause) | ||
if !ok { | ||
continue | ||
} | ||
for i := range cl.List { | ||
if selExpr, ok := cl.List[i].(*ast.SelectorExpr); ok { | ||
xid, ok := selExpr.X.(*ast.Ident) | ||
require.True(t, ok) | ||
require.Equal(t, "protocol", xid.Name) | ||
foundTags = append(foundTags, selExpr.Sel.Name) | ||
} | ||
} | ||
} | ||
} | ||
return true | ||
} | ||
|
||
readLoopFound := false | ||
ast.Inspect(f, func(n ast.Node) bool { | ||
// look for "readLoop" function | ||
fn, ok := n.(*ast.FuncDecl) | ||
if ok && fn.Name.Name == "readLoop" { | ||
readLoopFound = true | ||
ast.Inspect(fn, getCases) | ||
return false | ||
} | ||
return true | ||
}) | ||
require.True(t, readLoopFound) | ||
require.NotEmpty(t, foundTags) | ||
sort.Strings(allTags) | ||
sort.Strings(foundTags) | ||
require.Equal(t, allTags, foundTags) | ||
} | ||
|
||
func getProtocolTags(t *testing.T) []string { | ||
file := filepath.Join("../protocol", "tags.go") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does is work for both There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I read in this blog post that go test sets the working directory to the package where the test is running even in these cases, so you can load up test data from local files/directories that are also in the package directory... it seems to be working from CI which is running from the base go-algorand dir |
||
fset := token.NewFileSet() | ||
f, _ := parser.ParseFile(fset, file, nil, parser.ParseComments) | ||
|
||
// look for const declarations in protocol/tags.go | ||
var declaredTags []string | ||
// Iterate through the declarations in the file | ||
for _, d := range f.Decls { | ||
genDecl, ok := d.(*ast.GenDecl) | ||
// Check if the declaration is a constant and if not, continue | ||
if !ok || genDecl.Tok != token.CONST { | ||
continue | ||
} | ||
// Iterate through the specs (specifications) in the declaration | ||
for _, spec := range genDecl.Specs { | ||
if valueSpec, ok := spec.(*ast.ValueSpec); ok { | ||
for _, n := range valueSpec.Names { | ||
declaredTags = append(declaredTags, n.Name) | ||
} | ||
} | ||
} | ||
} | ||
// assert these AST-discovered tags are complete (match the size of protocol.TagList) | ||
require.Len(t, declaredTags, len(protocol.TagList)) | ||
return declaredTags | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright (C) 2019-2023 Algorand, Inc. | ||
// This file is part of go-algorand | ||
// | ||
// go-algorand is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU Affero General Public License as | ||
// published by the Free Software Foundation, either version 3 of the | ||
// License, or (at your option) any later version. | ||
// | ||
// go-algorand 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 Affero General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU Affero General Public License | ||
// along with go-algorand. If not, see <https://www.gnu.org/licenses/>. | ||
|
||
package protocol | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
|
||
"github.com/algorand/go-algorand/test/partitiontest" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// TestHashIDPrefix checks if any HashID const declared in hash.go is a prefix of another. | ||
func TestHashIDPrefix(t *testing.T) { | ||
t.Parallel() | ||
partitiontest.PartitionTest(t) | ||
|
||
values := getConstValues(t, "hash.go", "HashID") | ||
for i, v1 := range values { | ||
for j, v2 := range values { | ||
if i == j { | ||
continue | ||
} | ||
assert.False(t, strings.HasPrefix(v1, v2), "HashID %s is a prefix of %s", v2, v1) | ||
} | ||
} | ||
} |
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.
Are we confident that go will never load this test package in production?
Why not keep this false, and whichever test that needs this feature, can set it to true then false, and not run in parallel.
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.
Test code can't be compiled into non-test packages, so it is safe.. but it is true that to parallelize the network tests we'd need to track down which ones needed this flag set. When I did this a while ago I think there were some tests that failed and so I didn't want to track down exactly which ones.