Skip to content

Commit addcb75

Browse files
tac0turtletac0turtle
andauthored
test: add cmd tests (#2218)
<!-- Please read and fill out this form before submitting your PR. Please make sure you have reviewed our contributors guide before submitting your first PR. NOTE: PR titles should follow semantic commits: https://www.conventionalcommits.org/en/v1.0.0/ --> ## Overview This pr is adding test cases for the commands. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new CLI command for displaying network information, replacing the previous node info command. - Added a new command for running a Rollkit node in "based" mode with configurable Ethereum and API options. - **Bug Fixes** - Improved output formatting for network and version commands for better readability. - **Tests** - Added comprehensive tests for the network info and version commands to ensure correct output and error handling. - **Chores** - Removed unused workflow jobs for pull request automation and reviewer assignment. - Updated documentation badges in the README. - **Refactor** - Streamlined command registration and delegated implementation to external packages for improved maintainability. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: tac0turtle <you@example.com>
1 parent bcd4db4 commit addcb75

10 files changed

Lines changed: 481 additions & 237 deletions

File tree

.github/workflows/housekeeping.yml

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,6 @@ jobs:
2121
run-projects: true
2222
project-url: https://github.com/orgs/rollkit/projects/7
2323

24-
add-pr-to-project:
25-
# ignore dependabot PRs
26-
if: ${{ github.event.pull_request && github.actor != 'dependabot[bot]' }}
27-
name: Add PRs to project
28-
uses: rollkit/.github/.github/workflows/reusable_housekeeping.yml@v0.5.0
29-
secrets: inherit
30-
permissions:
31-
issues: write
32-
pull-requests: write
33-
with:
34-
run-projects: true
35-
project-url: https://github.com/orgs/rollkit/projects/7
36-
37-
auto-add-reviewer:
38-
name: Auto add reviewer to PR
39-
if: github.event.pull_request
40-
uses: rollkit/.github/.github/workflows/reusable_housekeeping.yml@v0.5.0
41-
secrets: inherit
42-
permissions:
43-
issues: write
44-
pull-requests: write
45-
with:
46-
run-auto-request-review: true
47-
4824
auto-add-assignee-pr:
4925
# ignore dependabot PRs
5026
if: ${{ github.event.pull_request && github.actor != 'dependabot[bot]' }}

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
Rollkit is the first sovereign rollup framework. For more in-depth information about Rollkit, please visit our [website][docs].
44

55
<!-- markdownlint-disable MD013 -->
6-
[![build-and-test](https://github.com/rollkit/rollkit/actions/workflows/test.yml/badge.svg)](https://github.com/rollkit/rollkit/actions/workflows/test.yml)
7-
[![golangci-lint](https://github.com/rollkit/rollkit/actions/workflows/lint.yml/badge.svg)](https://github.com/rollkit/rollkit/actions/workflows/lint.yml)
86
[![Go Report Card](https://goreportcard.com/badge/github.com/rollkit/rollkit)](https://goreportcard.com/report/github.com/rollkit/rollkit)
97
[![codecov](https://codecov.io/gh/rollkit/rollkit/branch/main/graph/badge.svg?token=CWGA4RLDS9)](https://codecov.io/gh/rollkit/rollkit)
108
[![GoDoc](https://godoc.org/github.com/rollkit/rollkit?status.svg)](https://godoc.org/github.com/rollkit/rollkit)

pkg/cmd/p2p.go

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"net/http"
77
"strings"
8+
"text/tabwriter"
89

910
"connectrpc.com/connect"
1011
"github.com/spf13/cobra"
@@ -14,8 +15,8 @@ import (
1415
)
1516

1617
// NodeInfoCmd returns information about the running node via RPC
17-
var NodeInfoCmd = &cobra.Command{
18-
Use: "node-info",
18+
var NetInfoCmd = &cobra.Command{
19+
Use: "net-info",
1920
Short: "Get information about a running node via RPC",
2021
Long: "This command retrieves the node information via RPC from a running node in the specified directory (or current directory if not specified).",
2122
RunE: func(cmd *cobra.Command, args []string) error {
@@ -52,24 +53,26 @@ var NodeInfoCmd = &cobra.Command{
5253
return fmt.Errorf("error calling GetNetInfo RPC: %w", err)
5354
}
5455

55-
// Print node information with better formatting
5656
netInfo := resp.Msg.NetInfo
57-
nodeID := netInfo.Id // Store Node ID separately
57+
nodeID := netInfo.Id
5858

59-
fmt.Println("\n" + strings.Repeat("=", 50))
60-
fmt.Println("📊 NODE INFORMATION")
61-
fmt.Println(strings.Repeat("=", 50))
62-
fmt.Printf("🆔 Node ID: \033[1;36m%s\033[0m\n", nodeID) // Print Node ID once
59+
out := cmd.OutOrStdout()
60+
w := tabwriter.NewWriter(out, 2, 0, 2, ' ', 0)
61+
62+
fmt.Fprintf(w, "%s", strings.Repeat("=", 50))
63+
fmt.Fprintf(w, "📊 NODE INFORMATION")
64+
fmt.Fprintf(w, "%s\n", strings.Repeat("=", 50))
65+
fmt.Fprintf(w, "🆔 Node ID: \033[1;36m%s\033[0m\n", nodeID) // Print Node ID once
6366

6467
// Iterate through all listen addresses
65-
fmt.Println("📡 Listen Addrs:")
68+
fmt.Fprintf(w, "📡 Listen Addrs:")
6669
for i, addr := range netInfo.ListenAddresses {
6770
fullAddress := fmt.Sprintf("%s/p2p/%s", addr, nodeID)
68-
fmt.Printf(" [%d] Addr: \033[1;36m%s\033[0m\n", i+1, addr)
69-
fmt.Printf(" Full: \033[1;32m%s\033[0m\n", fullAddress)
71+
fmt.Fprintf(w, " [%d] Addr: \033[1;36m%s\033[0m\n", i+1, addr)
72+
fmt.Fprintf(w, " Full: \033[1;32m%s\033[0m\n", fullAddress)
7073
}
7174

72-
fmt.Println(strings.Repeat("-", 50))
75+
fmt.Fprintf(w, "%s\n", strings.Repeat("-", 50))
7376
// Also get peer information
7477
peerResp, err := p2pClient.GetPeerInfo(
7578
context.Background(),
@@ -81,26 +84,27 @@ var NodeInfoCmd = &cobra.Command{
8184

8285
// Print connected peers in a table-like format
8386
peerCount := len(peerResp.Msg.Peers)
84-
fmt.Printf("👥 CONNECTED PEERS: \033[1;33m%d\033[0m\n", peerCount)
87+
fmt.Fprintf(w, "👥 CONNECTED PEERS: \033[1;33m%d\033[0m\n", peerCount)
8588

8689
if peerCount > 0 {
87-
fmt.Println(strings.Repeat("-", 50))
88-
fmt.Printf("%-5s %-20s %s\n", "NO.", "PEER ID", "ADDRESS")
89-
fmt.Println(strings.Repeat("-", 50))
90+
fmt.Fprintf(w, "%s\n", strings.Repeat("-", 50))
91+
fmt.Fprintf(w, "%-5s %-20s %s\n", "NO.", "PEER ID", "ADDRESS")
92+
fmt.Fprintf(w, "%s\n", strings.Repeat("-", 50))
9093

9194
for i, peer := range peerResp.Msg.Peers {
9295
// Truncate peer ID if it's too long for display
9396
peerID := peer.Id
9497
if len(peerID) > 18 {
9598
peerID = peerID[:15] + "..."
9699
}
97-
fmt.Printf("%-5d \033[1;34m%-20s\033[0m %s\n", i+1, peerID, peer.Address)
100+
fmt.Fprintf(w, "%-5d \033[1;34m%-20s\033[0m %s\n", i+1, peerID, peer.Address)
98101
}
99102
} else {
100-
fmt.Println("\n\033[3;33mNo peers connected\033[0m")
103+
fmt.Fprintf(w, "\n\033[3;33mNo peers connected\033[0m")
101104
}
102105

103-
fmt.Println(strings.Repeat("=", 50) + "\n")
106+
fmt.Fprintf(w, "%s\n", strings.Repeat("=", 50))
107+
w.Flush()
104108

105109
return nil
106110
},

pkg/cmd/p2p_test.go

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
package cmd
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"fmt"
7+
"net/http"
8+
"net/http/httptest"
9+
"os"
10+
"strings"
11+
"testing"
12+
13+
"github.com/libp2p/go-libp2p/core/peer"
14+
"github.com/multiformats/go-multiaddr"
15+
"github.com/spf13/cobra"
16+
"github.com/spf13/viper"
17+
"github.com/stretchr/testify/assert"
18+
"github.com/stretchr/testify/require"
19+
20+
"github.com/rollkit/rollkit/pkg/config"
21+
"github.com/rollkit/rollkit/pkg/p2p"
22+
"github.com/rollkit/rollkit/pkg/rpc/server"
23+
testmocks "github.com/rollkit/rollkit/test/mocks"
24+
"github.com/rollkit/rollkit/types/pb/rollkit/v1/v1connect"
25+
)
26+
27+
type contextKey string
28+
29+
const viperKey contextKey = "viper"
30+
31+
// executeCommandC executes the command and captures its output
32+
func executeCommandC(root *cobra.Command, args ...string) (string, error) {
33+
buf := new(bytes.Buffer)
34+
root.SetOut(buf)
35+
root.SetErr(buf)
36+
root.SetArgs(args)
37+
38+
err := root.Execute()
39+
return strings.TrimSpace(buf.String()), err
40+
}
41+
42+
func TestNetInfoCmd_Success(t *testing.T) {
43+
assert := assert.New(t)
44+
require := require.New(t)
45+
46+
mockP2P := new(testmocks.P2PRPC)
47+
48+
mockNodeID := "12D3KooWExampleNodeID1234567890"
49+
mockListenAddr1 := "/ip4/127.0.0.1/tcp/7676"
50+
mockListenAddr2 := "/ip6/::1/tcp/7677"
51+
mockPeerID1Str := "12D3KooWJHLDoXhmgYe6FEbujPzMQJvJ9JyGwRR2VjRM4f7Udvte"
52+
mockPeerAddr1Str := "/ip4/192.168.1.100/tcp/7676"
53+
mockPeerID2Str := "12D3KooWJHLDoXhmgYe6FEbujPzMQJvJ9JyGwRR2VjRM4f7Udvte"
54+
mockPeerAddr2Str := "/ip4/192.168.1.101/tcp/7676"
55+
56+
mockNetInfo := p2p.NetworkInfo{
57+
ID: mockNodeID,
58+
ListenAddress: []string{mockListenAddr1, mockListenAddr2},
59+
}
60+
61+
peerID1, err := peer.Decode(mockPeerID1Str)
62+
require.NoError(err)
63+
peerMultiaddr1, err := multiaddr.NewMultiaddr(mockPeerAddr1Str)
64+
require.NoError(err)
65+
addrInfo1 := peer.AddrInfo{ID: peerID1, Addrs: []multiaddr.Multiaddr{peerMultiaddr1}}
66+
67+
peerID2, err := peer.Decode(mockPeerID2Str)
68+
require.NoError(err)
69+
peerMultiaddr2, err := multiaddr.NewMultiaddr(mockPeerAddr2Str)
70+
require.NoError(err)
71+
addrInfo2 := peer.AddrInfo{ID: peerID2, Addrs: []multiaddr.Multiaddr{peerMultiaddr2}}
72+
73+
mockPeers := []peer.AddrInfo{addrInfo1, addrInfo2}
74+
75+
mockP2P.On("GetNetworkInfo").Return(mockNetInfo, nil)
76+
mockP2P.On("GetPeers").Return(mockPeers, nil)
77+
78+
p2pServer := server.NewP2PServer(mockP2P)
79+
mux := http.NewServeMux()
80+
81+
p2pPath, p2pHandler := v1connect.NewP2PServiceHandler(p2pServer)
82+
mux.Handle(p2pPath, p2pHandler)
83+
84+
httpServer := httptest.NewServer(mux)
85+
defer httpServer.Close()
86+
87+
tempDir, err := os.MkdirTemp("", "rollkit-test-home-*")
88+
require.NoError(err)
89+
defer os.RemoveAll(tempDir)
90+
91+
v := viper.New()
92+
rpcAddr := strings.TrimPrefix(httpServer.URL, "http://")
93+
v.Set(config.FlagRPCAddress, rpcAddr)
94+
v.Set(config.FlagRootDir, tempDir)
95+
96+
rootCmd := &cobra.Command{Use: "root"}
97+
rootCmd.PersistentFlags().String(config.FlagRootDir, tempDir, "Root directory for config and data")
98+
rootCmd.PersistentFlags().String(config.FlagRPCAddress, rpcAddr, "RPC listen address")
99+
100+
err = v.BindPFlag(config.FlagRootDir, rootCmd.PersistentFlags().Lookup(config.FlagRootDir))
101+
require.NoError(err)
102+
err = v.BindPFlag(config.FlagRPCAddress, rootCmd.PersistentFlags().Lookup(config.FlagRPCAddress))
103+
require.NoError(err)
104+
105+
NetInfoCmd.SetContext(context.WithValue(context.Background(), viperKey, v))
106+
rootCmd.AddCommand(NetInfoCmd)
107+
108+
output, err := executeCommandC(rootCmd, "net-info", "--rollkit.rpc.address="+rpcAddr)
109+
110+
require.NoError(err, "Command execution failed: %s", output)
111+
t.Log("Command Output:\n", output)
112+
113+
assert.Contains(output, "NODE INFORMATION")
114+
assert.Contains(output, fmt.Sprintf("Node ID: \033[1;36m%s\033[0m", mockNodeID))
115+
assert.Contains(output, "Listen Addrs:")
116+
assert.Contains(output, fmt.Sprintf("Addr: \033[1;36m%s\033[0m", mockListenAddr1))
117+
assert.Contains(output, fmt.Sprintf("Full: \033[1;32m%s/p2p/%s\033[0m", mockListenAddr1, mockNodeID))
118+
assert.Contains(output, fmt.Sprintf("Addr: \033[1;36m%s\033[0m", mockListenAddr2))
119+
assert.Contains(output, fmt.Sprintf("Full: \033[1;32m%s/p2p/%s\033[0m", mockListenAddr2, mockNodeID))
120+
121+
assert.Contains(output, "CONNECTED PEERS: \033[1;33m2\033[0m")
122+
assert.Contains(output, "PEER ID")
123+
assert.Contains(output, "ADDRESS")
124+
125+
truncatedPeerID1 := mockPeerID1Str[:15] + "..."
126+
expectedPeerAddrOutput1 := addrInfo1.String()
127+
assert.Contains(output, fmt.Sprintf("%-5d \033[1;34m%-20s\033[0m %s", 1, truncatedPeerID1, expectedPeerAddrOutput1), "Peer 1 details mismatch")
128+
129+
truncatedPeerID2 := mockPeerID2Str[:15] + "..."
130+
expectedPeerAddrOutput2 := addrInfo2.String()
131+
assert.Contains(output, fmt.Sprintf("%-5d \033[1;34m%-20s\033[0m %s", 2, truncatedPeerID2, expectedPeerAddrOutput2), "Peer 2 details mismatch")
132+
133+
mockP2P.AssertExpectations(t)
134+
}
135+
136+
func TestNetInfoCmd_NoPeers(t *testing.T) {
137+
assert := assert.New(t)
138+
require := require.New(t)
139+
140+
mockP2P := new(testmocks.P2PRPC)
141+
142+
mockNodeID := "12D3KooWExampleNodeID1234567890"
143+
mockListenAddr1 := "/ip4/127.0.0.1/tcp/7676"
144+
mockListenAddr2 := "/ip6/::1/tcp/7677"
145+
146+
mockNetInfo := p2p.NetworkInfo{
147+
ID: mockNodeID,
148+
ListenAddress: []string{mockListenAddr1, mockListenAddr2},
149+
}
150+
151+
mockPeers := []peer.AddrInfo{}
152+
153+
mockP2P.On("GetNetworkInfo").Return(mockNetInfo, nil)
154+
mockP2P.On("GetPeers").Return(mockPeers, nil)
155+
156+
p2pServer := server.NewP2PServer(mockP2P)
157+
mux := http.NewServeMux()
158+
p2pPath, p2pHandler := v1connect.NewP2PServiceHandler(p2pServer)
159+
mux.Handle(p2pPath, p2pHandler)
160+
161+
httpServer := httptest.NewServer(mux)
162+
defer httpServer.Close()
163+
164+
tempDir, err := os.MkdirTemp("", "rollkit-test-home-nopeer-*")
165+
require.NoError(err)
166+
defer os.RemoveAll(tempDir)
167+
168+
// Configure Viper to use the test server's address and temp home
169+
v := viper.New()
170+
rpcAddr := strings.TrimPrefix(httpServer.URL, "http://")
171+
v.Set(config.FlagRPCAddress, rpcAddr)
172+
v.Set(config.FlagRootDir, tempDir)
173+
174+
rootCmd := &cobra.Command{Use: "root"}
175+
rootCmd.PersistentFlags().String(config.FlagRootDir, tempDir, "Root directory for config and data")
176+
rootCmd.PersistentFlags().String(config.FlagRPCAddress, rpcAddr, "RPC listen address")
177+
178+
err = v.BindPFlag(config.FlagRootDir, rootCmd.PersistentFlags().Lookup(config.FlagRootDir))
179+
require.NoError(err)
180+
err = v.BindPFlag(config.FlagRPCAddress, rootCmd.PersistentFlags().Lookup(config.FlagRPCAddress))
181+
require.NoError(err)
182+
183+
NetInfoCmd.SetContext(context.WithValue(context.Background(), viperKey, v))
184+
rootCmd.AddCommand(NetInfoCmd)
185+
186+
output, err := executeCommandC(rootCmd, "net-info", "--rollkit.rpc.address="+rpcAddr)
187+
188+
require.NoError(err, "Command execution failed: %s", output)
189+
t.Log("Command Output:\n", output)
190+
191+
assert.Contains(output, "NODE INFORMATION")
192+
assert.Contains(output, fmt.Sprintf("Node ID: \033[1;36m%s\033[0m", mockNodeID))
193+
assert.Contains(output, "Listen Addrs:")
194+
assert.Contains(output, fmt.Sprintf("Addr: \033[1;36m%s\033[0m", mockListenAddr1))
195+
assert.Contains(output, fmt.Sprintf("Full: \033[1;32m%s/p2p/%s\033[0m", mockListenAddr1, mockNodeID))
196+
assert.Contains(output, fmt.Sprintf("Addr: \033[1;36m%s\033[0m", mockListenAddr2))
197+
assert.Contains(output, fmt.Sprintf("Full: \033[1;32m%s/p2p/%s\033[0m", mockListenAddr2, mockNodeID))
198+
199+
assert.Contains(output, "CONNECTED PEERS: \033[1;33m0\033[0m")
200+
assert.Contains(output, "No peers connected")
201+
202+
mockP2P.AssertExpectations(t)
203+
}

pkg/cmd/version.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package cmd
33
import (
44
"errors"
55
"fmt"
6-
"os"
76
"text/tabwriter"
87

98
"github.com/spf13/cobra"
@@ -28,7 +27,8 @@ var VersionCmd = &cobra.Command{
2827
if Version == "" {
2928
return errors.New("version not set")
3029
}
31-
w := tabwriter.NewWriter(os.Stdout, 2, 0, 2, ' ', 0)
30+
out := cmd.OutOrStdout()
31+
w := tabwriter.NewWriter(out, 2, 0, 2, ' ', 0)
3232
_, err1 := fmt.Fprintf(w, "\nrollkit version:\t%v\n", Version)
3333
_, err2 := fmt.Fprintf(w, "rollkit git sha:\t%v\n", GitSHA)
3434
_, err3 := fmt.Fprintln(w, "")

0 commit comments

Comments
 (0)