Skip to content

Commit 5d20fbb

Browse files
authored
cmd/devp2p, internal/utesting: implement TAP output (#21760)
TAP is a text format for test results. Parsers for it are available in many languages, making it easy to consume. I want TAP output from our protocol tests because the Hive wrapper around them needs to know about the test names and their individual results and logs. It would also be possible to just write this info as JSON, but I don't want to invent a new format. This also improves the normal console output for tests (when running without --tap). It now prints -- RUN lines before any output from the test, and indents the log output by one space.
1 parent e640267 commit 5d20fbb

File tree

6 files changed

+329
-81
lines changed

6 files changed

+329
-81
lines changed

cmd/devp2p/discv4cmd.go

+9-29
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,12 @@ package main
1919
import (
2020
"fmt"
2121
"net"
22-
"os"
2322
"strings"
2423
"time"
2524

2625
"github.com/ethereum/go-ethereum/cmd/devp2p/internal/v4test"
2726
"github.com/ethereum/go-ethereum/common"
2827
"github.com/ethereum/go-ethereum/crypto"
29-
"github.com/ethereum/go-ethereum/internal/utesting"
3028
"github.com/ethereum/go-ethereum/p2p/discover"
3129
"github.com/ethereum/go-ethereum/p2p/enode"
3230
"github.com/ethereum/go-ethereum/params"
@@ -82,7 +80,13 @@ var (
8280
Name: "test",
8381
Usage: "Runs tests against a node",
8482
Action: discv4Test,
85-
Flags: []cli.Flag{remoteEnodeFlag, testPatternFlag, testListen1Flag, testListen2Flag},
83+
Flags: []cli.Flag{
84+
remoteEnodeFlag,
85+
testPatternFlag,
86+
testTAPFlag,
87+
testListen1Flag,
88+
testListen2Flag,
89+
},
8690
}
8791
)
8892

@@ -113,20 +117,6 @@ var (
113117
Usage: "Enode of the remote node under test",
114118
EnvVar: "REMOTE_ENODE",
115119
}
116-
testPatternFlag = cli.StringFlag{
117-
Name: "run",
118-
Usage: "Pattern of test suite(s) to run",
119-
}
120-
testListen1Flag = cli.StringFlag{
121-
Name: "listen1",
122-
Usage: "IP address of the first tester",
123-
Value: v4test.Listen1,
124-
}
125-
testListen2Flag = cli.StringFlag{
126-
Name: "listen2",
127-
Usage: "IP address of the second tester",
128-
Value: v4test.Listen2,
129-
}
130120
)
131121

132122
func discv4Ping(ctx *cli.Context) error {
@@ -213,6 +203,7 @@ func discv4Crawl(ctx *cli.Context) error {
213203
return nil
214204
}
215205

206+
// discv4Test runs the protocol test suite.
216207
func discv4Test(ctx *cli.Context) error {
217208
// Configure test package globals.
218209
if !ctx.IsSet(remoteEnodeFlag.Name) {
@@ -221,18 +212,7 @@ func discv4Test(ctx *cli.Context) error {
221212
v4test.Remote = ctx.String(remoteEnodeFlag.Name)
222213
v4test.Listen1 = ctx.String(testListen1Flag.Name)
223214
v4test.Listen2 = ctx.String(testListen2Flag.Name)
224-
225-
// Filter and run test cases.
226-
tests := v4test.AllTests
227-
if ctx.IsSet(testPatternFlag.Name) {
228-
tests = utesting.MatchTests(tests, ctx.String(testPatternFlag.Name))
229-
}
230-
results := utesting.RunTests(tests, os.Stdout)
231-
if fails := utesting.CountFailures(results); fails > 0 {
232-
return fmt.Errorf("%v/%v tests passed.", len(tests)-fails, len(tests))
233-
}
234-
fmt.Printf("%v/%v passed\n", len(tests), len(tests))
235-
return nil
215+
return runTests(ctx, v4test.AllTests)
236216
}
237217

238218
// startV4 starts an ephemeral discovery V4 node.

cmd/devp2p/discv5cmd.go

+8-20
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,10 @@ package main
1818

1919
import (
2020
"fmt"
21-
"os"
2221
"time"
2322

2423
"github.com/ethereum/go-ethereum/cmd/devp2p/internal/v5test"
2524
"github.com/ethereum/go-ethereum/common"
26-
"github.com/ethereum/go-ethereum/internal/utesting"
27-
"github.com/ethereum/go-ethereum/log"
2825
"github.com/ethereum/go-ethereum/p2p/discover"
2926
"gopkg.in/urfave/cli.v1"
3027
)
@@ -62,7 +59,12 @@ var (
6259
Name: "test",
6360
Usage: "Runs protocol tests against a node",
6461
Action: discv5Test,
65-
Flags: []cli.Flag{testPatternFlag, testListen1Flag, testListen2Flag},
62+
Flags: []cli.Flag{
63+
testPatternFlag,
64+
testTAPFlag,
65+
testListen1Flag,
66+
testListen2Flag,
67+
},
6668
}
6769
discv5ListenCommand = cli.Command{
6870
Name: "listen",
@@ -114,28 +116,14 @@ func discv5Crawl(ctx *cli.Context) error {
114116
return nil
115117
}
116118

119+
// discv5Test runs the protocol test suite.
117120
func discv5Test(ctx *cli.Context) error {
118-
// Disable logging unless explicitly enabled.
119-
if !ctx.GlobalIsSet("verbosity") && !ctx.GlobalIsSet("vmodule") {
120-
log.Root().SetHandler(log.DiscardHandler())
121-
}
122-
123-
// Filter and run test cases.
124121
suite := &v5test.Suite{
125122
Dest: getNodeArg(ctx),
126123
Listen1: ctx.String(testListen1Flag.Name),
127124
Listen2: ctx.String(testListen2Flag.Name),
128125
}
129-
tests := suite.AllTests()
130-
if ctx.IsSet(testPatternFlag.Name) {
131-
tests = utesting.MatchTests(tests, ctx.String(testPatternFlag.Name))
132-
}
133-
results := utesting.RunTests(tests, os.Stdout)
134-
if fails := utesting.CountFailures(results); fails > 0 {
135-
return fmt.Errorf("%v/%v tests passed.", len(tests)-fails, len(tests))
136-
}
137-
fmt.Printf("%v/%v passed\n", len(tests), len(tests))
138-
return nil
126+
return runTests(ctx, suite.AllTests())
139127
}
140128

141129
func discv5Listen(ctx *cli.Context) error {

cmd/devp2p/rlpxcmd.go

+7-17
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ package main
1919
import (
2020
"fmt"
2121
"net"
22-
"os"
2322

2423
"github.com/ethereum/go-ethereum/cmd/devp2p/internal/ethtest"
2524
"github.com/ethereum/go-ethereum/crypto"
26-
"github.com/ethereum/go-ethereum/internal/utesting"
2725
"github.com/ethereum/go-ethereum/p2p"
2826
"github.com/ethereum/go-ethereum/p2p/rlpx"
2927
"github.com/ethereum/go-ethereum/rlp"
@@ -47,9 +45,12 @@ var (
4745
rlpxEthTestCommand = cli.Command{
4846
Name: "eth-test",
4947
Usage: "Runs tests against a node",
50-
ArgsUsage: "<node> <path_to_chain.rlp_file>",
48+
ArgsUsage: "<node> <chain.rlp> <genesis.json>",
5149
Action: rlpxEthTest,
52-
Flags: []cli.Flag{testPatternFlag},
50+
Flags: []cli.Flag{
51+
testPatternFlag,
52+
testTAPFlag,
53+
},
5354
}
5455
)
5556

@@ -88,22 +89,11 @@ func rlpxPing(ctx *cli.Context) error {
8889
return nil
8990
}
9091

92+
// rlpxEthTest runs the eth protocol test suite.
9193
func rlpxEthTest(ctx *cli.Context) error {
9294
if ctx.NArg() < 3 {
9395
exit("missing path to chain.rlp as command-line argument")
9496
}
95-
9697
suite := ethtest.NewSuite(getNodeArg(ctx), ctx.Args()[1], ctx.Args()[2])
97-
98-
// Filter and run test cases.
99-
tests := suite.AllTests()
100-
if ctx.IsSet(testPatternFlag.Name) {
101-
tests = utesting.MatchTests(tests, ctx.String(testPatternFlag.Name))
102-
}
103-
results := utesting.RunTests(tests, os.Stdout)
104-
if fails := utesting.CountFailures(results); fails > 0 {
105-
return fmt.Errorf("%v of %v tests passed.", len(tests)-fails, len(tests))
106-
}
107-
fmt.Printf("all tests passed\n")
108-
return nil
98+
return runTests(ctx, suite.AllTests())
10999
}

cmd/devp2p/runtest.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2020 The go-ethereum Authors
2+
// This file is part of go-ethereum.
3+
//
4+
// go-ethereum is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// go-ethereum is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package main
18+
19+
import (
20+
"os"
21+
22+
"github.com/ethereum/go-ethereum/cmd/devp2p/internal/v4test"
23+
"github.com/ethereum/go-ethereum/internal/utesting"
24+
"github.com/ethereum/go-ethereum/log"
25+
"gopkg.in/urfave/cli.v1"
26+
)
27+
28+
var (
29+
testPatternFlag = cli.StringFlag{
30+
Name: "run",
31+
Usage: "Pattern of test suite(s) to run",
32+
}
33+
testTAPFlag = cli.BoolFlag{
34+
Name: "tap",
35+
Usage: "Output TAP",
36+
}
37+
// These two are specific to the discovery tests.
38+
testListen1Flag = cli.StringFlag{
39+
Name: "listen1",
40+
Usage: "IP address of the first tester",
41+
Value: v4test.Listen1,
42+
}
43+
testListen2Flag = cli.StringFlag{
44+
Name: "listen2",
45+
Usage: "IP address of the second tester",
46+
Value: v4test.Listen2,
47+
}
48+
)
49+
50+
func runTests(ctx *cli.Context, tests []utesting.Test) error {
51+
// Filter test cases.
52+
if ctx.IsSet(testPatternFlag.Name) {
53+
tests = utesting.MatchTests(tests, ctx.String(testPatternFlag.Name))
54+
}
55+
// Disable logging unless explicitly enabled.
56+
if !ctx.GlobalIsSet("verbosity") && !ctx.GlobalIsSet("vmodule") {
57+
log.Root().SetHandler(log.DiscardHandler())
58+
}
59+
// Run the tests.
60+
var run = utesting.RunTests
61+
if ctx.Bool(testTAPFlag.Name) {
62+
run = utesting.RunTAP
63+
}
64+
results := run(tests, os.Stdout)
65+
if utesting.CountFailures(results) > 0 {
66+
os.Exit(1)
67+
}
68+
return nil
69+
}

0 commit comments

Comments
 (0)